PSSK
Mpdf.php
Go to the documentation of this file.
1<?php
2
3namespace Mpdf;
4
10use Mpdf\Log\Context as LogContext;
13use Mpdf\QrCode;
19
29{
30
31 use Strict;
32 use FpdiTrait;
33
34 const VERSION = '8.0.13';
35
36 const SCALE = 72 / 25.4;
37
39 var $useFixedTextBaseline; // mPDF 6
41 var $interpolateImages; // mPDF 6
42 var $defaultPagebreakType; // mPDF 6 pagebreaktype
43 var $indexUseSubentries; // mPDF 6
44
45 var $autoScriptToLang; // mPDF 6
46 var $baseScript; // mPDF 6
47 var $autoVietnamese; // mPDF 6
48 var $autoArabic; // mPDF 6
49
52 var $h2toc;
56
59
63
71
72 var $PDFX;
74
75 var $PDFA;
76 var $PDFAversion = '1-B';
79
84
93
95
96 var $dpi;
104
106
117
124
125 // PageNumber Conditional Text
128
149
150 var $list_auto_mode; // mPDF 6
152 var $list_indent_default; // mPDF 6
154 var $list_marker_offset; // mPDF 6
156
159
167
172
174
181
183
186
195
198 var $pregCURSchars; // mPDF 6
199
206
209
211
212 var $defaultPageNumStyle; // mPDF 6
213
215 // INTERNAL VARIABLES
217 var $extrapagebreak; // mPDF 6 pagebreaktype
218
219 var $uniqstr; // mPDF 5.7.2
221
222 var $textvar; // mPDF 5.7.1
223 var $fontLanguageOverride; // mPDF 5.7.1
224 var $OTLtags; // mPDF 5.7.1
225 var $OTLdata; // mPDF 5.7.1
226
229
237
241
243
247
249
255
262
271
274
279
281
282 private $fontDir;
283
285
287
289
291
295
296 // mPDF 5.7.3 inline text-decoration parameters
301
306
308
309 var $inFixedPosBlock; // Internal flag for position:fixed block
310 var $fixedPosBlock; // Buffer string for position:fixed block
317
319
320 var $docTemplateStart; // Internal flag for page (page no. -1) that docTemplate starts on
321
323
325
340
343
346
350
351 var $writingHTMLheader; // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
353
355
357
361
364
367
370
373
376
378
383
391
392 var $formobjects; // array of Form Objects for WMF
395 var $InlineBDF; // mPDF 6 Bidirectional formatting
396 var $InlineBDFctr; // mPDF 6
397
404
406
407 var $pageDim; // Keep track of page wxh for orientation changes - set in _beginpage, used in _putannots
408
410
416
419
424
426
427 var $show_marks; // crop or cross marks
429
431 var $kwt;
439
441
445
447
454
457
460
464
465 // See Config\FontVariables for these next 5 values
471
472 // List of ALL available CJK fonts (incl. styles) (Adobe add-ons) hw removed
474
480
481 // CJK fonts
486
487 // SetProtection
489
490 var $enc_obj_id; // encryption object id
491
492 // Bookmark
495
496 // INDEX
501 var $y0; // Top ordinate of columns
502
503 var $ColL;
506
507 // COLUMNS
508 var $ColR;
514
515 // Substitutions
516 var $substitute; // Array of substitution strings e.g. <ttz>112</ttz>
517 var $entsearch; // Array of HTML entities (>ASCII 127) to substitute
518 var $entsubstitute; // Array of substitution decimal unicode for the Hi entities
519
520 // Default values if no style sheet offered (cf. http://www.w3.org/TR/CSS21/sample.html)
523
524 var $lastoptionaltag; // Save current block item which HTML specifies optionsl endtag
527 var $blk;
530
531 var $ws; // Word spacing
532
533 var $HREF;
536 var $oldx;
537 var $oldy;
538 var $B;
539 var $I;
540
543 var $cell;
544 var $col;
545 var $row;
546
551
552 // mPDF 6 Used for table cell (block-type) properties
557
558 // mPDF 6 Lists
563
567 var $BIG;
570
579
584
588
589 // Table Rotation
596
597 var $keep_block_together; // Keep a Block from page-break-inside: avoid
598
603
607
609
610 var $extgstates; // Used for alpha channel - Transparency (Watermark)
611 var $mgl;
612 var $mgt;
613 var $mgr;
614 var $mgb;
615
616 var $tts;
617 var $ttz;
618 var $tta;
619
620 // Best to alter the below variables using default stylesheet above
623 var $default_font_size; // in pts
624 var $original_default_font_size; // used to save default sizes when using table default
628
629 // TABLE
643
645
652
653 var $shrin_k; // factor with which to shrink tables - used internally - do not change
654 var $shrink_this_table_to_fit; // 0 or false to disable; value (if set) gives maximum factor to reduce fontsize
655 var $MarginCorrection; // corrects for OddEven Margins
658
662
663 var $js;
664
671
678
685
696
705
714
723
732
733 // Private properties FROM FPDF
736
737 var $page; // current page number
738
739 var $n; // current object number
740 var $n_js; // current object number
741
745
746 var $offsets; // array of object offsets
747 var $buffer; // buffer holding in-memory PDF
748 var $pages; // array containing pages
749 var $state; // current document state
750 var $compress; // compression flag
751
752 var $DefOrientation; // default orientation
753 var $CurOrientation; // current orientation
754 var $OrientationChanges; // array indicating orientation changes
755
756 var $fwPt;
757 var $fhPt; // dimensions of page format in points
758 var $fw;
759 var $fh; // dimensions of page format in user unit
760 var $wPt;
761 var $hPt; // current dimensions of page in points
762
763 var $w;
764 var $h; // current dimensions of page in user unit
765
766 var $lMargin; // left margin
767 var $tMargin; // top margin
768 var $rMargin; // right margin
769 var $bMargin; // page break margin
770 var $cMarginL; // cell margin Left
771 var $cMarginR; // cell margin Right
772 var $cMarginT; // cell margin Left
773 var $cMarginB; // cell margin Right
774
775 var $DeflMargin; // Default left margin
776 var $DefrMargin; // Default right margin
777
778 var $x;
779 var $y; // current position in user unit for cell positioning
780
781 var $lasth; // height of last cell printed
782 var $LineWidth; // line width in user unit
783
784 var $CoreFonts; // array of standard font names
785 var $fonts; // array of used fonts
786 var $FontFiles; // array of font files
787
788 var $images; // array of used images
789 var $imageVars = []; // array of image vars
790
791 var $PageLinks; // array of links in pages
792 var $links; // array of internal links
793 var $FontFamily; // current font family
794 var $FontStyle; // current font style
795 var $CurrentFont; // current font info
796 var $FontSizePt; // current font size in points
797 var $FontSize; // current font size in user unit
798 var $DrawColor; // commands for drawing color
799 var $FillColor; // commands for filling color
800 var $TextColor; // commands for text color
801 var $ColorFlag; // indicates whether fill and text colors are different
802 var $autoPageBreak; // automatic page breaking
803 var $PageBreakTrigger; // threshold used to trigger page breaks
804 var $InFooter; // flag set when processing footer
805
807 var $processingFooter; // flag set when processing footer - added for columns
808 var $processingHeader; // flag set when processing header - added for columns
809 var $ZoomMode; // zoom display mode
810 var $LayoutMode; // layout display mode
811 var $title; // title
812 var $subject; // subject
813 var $author; // author
814 var $keywords; // keywords
815 var $creator; // creator
816
817 var $customProperties; // array of custom document properties
818
819 var $associatedFiles; // associated files (see SetAssociatedFiles below)
820 var $additionalXmpRdf; // additional rdf added in xmp
821
822 var $aliasNbPg; // alias for total number of pages
823 var $aliasNbPgGp; // alias for total number of pages in page group
824
828
830
831 private $preambleWritten = false;
832
836 private $fontDescriptor;
837
841 private $otl;
842
846 private $cssManager;
847
851 private $gradient;
852
856 private $bmp;
857
861 private $wmf;
862
866 private $tableOfContents;
867
871 private $form;
872
876 private $directWrite;
877
881 private $cache;
882
886 private $fontCache;
887
891 private $fontFileFinder;
892
896 private $tag;
897
902 public $barcode;
903
907 private $qrcode;
908
912 private $sizeConverter;
913
917 private $colorConverter;
918
922 private $colorModeConverter;
923
927 private $colorSpaceRestrictor;
928
932 private $hyphenator;
933
937 private $protection;
938
942 private $remoteContentFetcher;
943
947 private $imageProcessor;
948
952 private $languageToFont;
953
957 private $scriptToLanguage;
958
962 private $logger;
963
967 private $writer;
968
972 private $fontWriter;
973
977 private $metadataWriter;
978
982 private $imageWriter;
983
987 private $formWriter;
988
992 private $pageWriter;
993
997 private $bookmarkWriter;
998
1002 private $optionalContentWriter;
1003
1007 private $colorWriter;
1008
1012 private $backgroundWriter;
1013
1017 private $javaScriptWriter;
1018
1022 private $resourceWriter;
1023
1027 private $services;
1028
1032 public function __construct(array $config = [])
1033 {
1034 $this->_dochecks();
1035
1036 list(
1037 $mode,
1038 $format,
1039 $default_font_size,
1040 $default_font,
1041 $mgl,
1042 $mgr,
1043 $mgt,
1044 $mgb,
1045 $mgh,
1046 $mgf,
1047 $orientation
1048 ) = $this->initConstructorParams($config);
1049
1050 $this->logger = new NullLogger();
1051
1052 $originalConfig = $config;
1053 $config = $this->initConfig($originalConfig);
1054
1055 $serviceFactory = new ServiceFactory();
1056 $services = $serviceFactory->getServices(
1057 $this,
1058 $this->logger,
1059 $config,
1060 $this->restrictColorSpace,
1061 $this->languageToFont,
1062 $this->scriptToLanguage,
1063 $this->fontDescriptor,
1064 $this->bmp,
1065 $this->directWrite,
1066 $this->wmf
1067 );
1068
1069 $this->services = [];
1070
1071 foreach ($services as $key => $service) {
1072 $this->{$key} = $service;
1073 $this->services[] = $key;
1074 }
1075
1076 $this->time0 = microtime(true);
1077
1078 $this->writingToC = false;
1079
1080 $this->layers = [];
1081 $this->current_layer = 0;
1082 $this->open_layer_pane = false;
1083
1084 $this->visibility = 'visible';
1085
1086 $this->tableBackgrounds = [];
1087 $this->uniqstr = '20110230'; // mPDF 5.7.2
1088 $this->kt_y00 = 0;
1089 $this->kt_p00 = 0;
1090 $this->BMPonly = [];
1091 $this->page = 0;
1092 $this->n = 2;
1093 $this->buffer = '';
1094 $this->objectbuffer = [];
1095 $this->pages = [];
1096 $this->OrientationChanges = [];
1097 $this->state = 0;
1098 $this->fonts = [];
1099 $this->FontFiles = [];
1100 $this->images = [];
1101 $this->links = [];
1102 $this->InFooter = false;
1103 $this->processingFooter = false;
1104 $this->processingHeader = false;
1105 $this->lasth = 0;
1106 $this->FontFamily = '';
1107 $this->FontStyle = '';
1108 $this->FontSizePt = 9;
1109
1110 // Small Caps
1111 $this->inMeter = false;
1112 $this->decimal_offset = 0;
1113
1114 $this->PDFAXwarnings = [];
1115
1116 $this->defTextColor = $this->TextColor = $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings), true);
1117 $this->defDrawColor = $this->DrawColor = $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings), true);
1118 $this->defFillColor = $this->FillColor = $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings), true);
1119
1120 $this->upperCase = require __DIR__ . '/../data/upperCase.php';
1121
1122 $this->extrapagebreak = true; // mPDF 6 pagebreaktype
1123
1124 $this->ColorFlag = false;
1125 $this->extgstates = [];
1126
1127 $this->mb_enc = 'windows-1252';
1128 $this->originalMbEnc = mb_internal_encoding();
1129 $this->originalMbRegexEnc = mb_regex_encoding();
1130
1131 $this->directionality = 'ltr';
1132 $this->defaultAlign = 'L';
1133 $this->defaultTableAlign = 'L';
1134
1135 $this->fixedPosBlockSave = [];
1136 $this->extraFontSubsets = 0;
1137
1138 $this->blockContext = 1;
1139 $this->floatDivs = [];
1140 $this->DisplayPreferences = '';
1141
1142 // Tiling patterns used for backgrounds
1143 $this->patterns = [];
1144 $this->pageBackgrounds = [];
1145 $this->gradients = [];
1146
1147 // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
1148 $this->writingHTMLheader = false;
1149 // internal flag - used both for writing HTMLHeaders/Footers and FixedPos block
1150 $this->writingHTMLfooter = false;
1151
1152 $this->kwt_Reference = [];
1153 $this->kwt_BMoutlines = [];
1154 $this->kwt_toc = [];
1155
1156 $this->tbrot_BMoutlines = [];
1157 $this->tbrot_toc = [];
1158
1159 $this->col_BMoutlines = [];
1160 $this->col_toc = [];
1161
1162 $this->pgsIns = [];
1163 $this->PDFAXwarnings = [];
1164 $this->inlineDisplayOff = false;
1165 $this->lSpacingCSS = '';
1166 $this->wSpacingCSS = '';
1167 $this->fixedlSpacing = false;
1168 $this->minwSpacing = 0;
1169
1170 // Baseline for text
1171 $this->baselineC = 0.35;
1172
1173 // mPDF 5.7.3 inline text-decoration parameters
1174 // Sets default change in baseline for <sup> text as factor of preceeding fontsize
1175 // 0.35 has been recommended; 0.5 matches applications like MS Word
1176 $this->baselineSup = 0.5;
1177
1178 // Sets default change in baseline for <sub> text as factor of preceeding fontsize
1179 $this->baselineSub = -0.2;
1180 // Sets default height for <strike> text as factor of fontsize
1181 $this->baselineS = 0.3;
1182 // Sets default height for overline text as factor of fontsize
1183 $this->baselineO = 1.1;
1184
1185 $this->noImageFile = __DIR__ . '/../data/no_image.jpg';
1186 $this->subPos = 0;
1187
1188 $this->fullImageHeight = false;
1189 $this->floatbuffer = [];
1190 $this->floatmargins = [];
1191 $this->formobjects = []; // array of Form Objects for WMF
1192 $this->InlineProperties = [];
1193 $this->InlineAnnots = [];
1194 $this->InlineBDF = []; // mPDF 6
1195 $this->InlineBDFctr = 0; // mPDF 6
1196 $this->tbrot_Annots = [];
1197 $this->kwt_Annots = [];
1198 $this->columnAnnots = [];
1199 $this->PageLinks = [];
1200 $this->OrientationChanges = [];
1201 $this->pageDim = [];
1202 $this->saveHTMLHeader = [];
1203 $this->saveHTMLFooter = [];
1204 $this->PageAnnots = [];
1205 $this->PageNumSubstitutions = [];
1206 $this->breakpoints = []; // used in columnbuffer
1207 $this->tableLevel = 0;
1208 $this->tbctr = []; // counter for nested tables at each level
1209 $this->page_box = [];
1210 $this->show_marks = ''; // crop or cross marks
1211 $this->kwt = false;
1212 $this->kwt_height = 0;
1213 $this->kwt_y0 = 0;
1214 $this->kwt_x0 = 0;
1215 $this->kwt_buffer = [];
1216 $this->kwt_Links = [];
1217 $this->kwt_moved = false;
1218 $this->kwt_saved = false;
1219 $this->PageNumSubstitutions = [];
1220 $this->base_table_properties = [];
1221 $this->borderstyles = ['inset', 'groove', 'outset', 'ridge', 'dotted', 'dashed', 'solid', 'double'];
1222 $this->tbrot_align = 'C';
1223
1224 $this->pageHTMLheaders = [];
1225 $this->pageHTMLfooters = [];
1226 $this->HTMLheaderPageLinks = [];
1227 $this->HTMLheaderPageAnnots = [];
1228
1229 $this->HTMLheaderPageForms = [];
1230 $this->columnForms = [];
1231 $this->tbrotForms = [];
1232
1233 $this->pageoutput = [];
1234
1235 $this->bufferoutput = false;
1236
1237 $this->encrypted = false;
1238
1239 $this->BMoutlines = [];
1240 $this->ColActive = 0; // Flag indicating that columns are on (the index is being processed)
1241 $this->Reference = []; // Array containing the references
1242 $this->CurrCol = 0; // Current column number
1243 $this->ColL = [0]; // Array of Left pos of columns - absolute - needs Margin correction for Odd-Even
1244 $this->ColR = [0]; // Array of Right pos of columns - absolute pos - needs Margin correction for Odd-Even
1245 $this->ChangeColumn = 0;
1246 $this->columnbuffer = [];
1247 $this->ColDetails = []; // Keeps track of some column details
1248 $this->columnLinks = []; // Cross references PageLinks
1249 $this->substitute = []; // Array of substitution strings e.g. <ttz>112</ttz>
1250 $this->entsearch = []; // Array of HTML entities (>ASCII 127) to substitute
1251 $this->entsubstitute = []; // Array of substitution decimal unicode for the Hi entities
1252 $this->lastoptionaltag = '';
1253 $this->charset_in = '';
1254 $this->blk = [];
1255 $this->blklvl = 0;
1256 $this->tts = false;
1257 $this->ttz = false;
1258 $this->tta = false;
1259 $this->ispre = false;
1260
1261 $this->checkSIP = false;
1262 $this->checkSMP = false;
1263 $this->checkCJK = false;
1264
1265 $this->page_break_after_avoid = false;
1266 $this->margin_bottom_collapse = false;
1267 $this->tablethead = 0;
1268 $this->tabletfoot = 0;
1269 $this->table_border_attr_set = 0;
1270 $this->table_border_css_set = 0;
1271 $this->shrin_k = 1.0;
1272 $this->shrink_this_table_to_fit = 0;
1273 $this->MarginCorrection = 0;
1274
1275 $this->tabletheadjustfinished = false;
1276 $this->usingCoreFont = false;
1277 $this->charspacing = 0;
1278
1279 $this->autoPageBreak = true;
1280
1281 $this->_setPageSize($format, $orientation);
1282 $this->DefOrientation = $orientation;
1283
1284 $this->margin_header = $mgh;
1285 $this->margin_footer = $mgf;
1286
1287 $bmargin = $mgb;
1288
1289 $this->DeflMargin = $mgl;
1290 $this->DefrMargin = $mgr;
1291
1292 $this->orig_tMargin = $mgt;
1293 $this->orig_bMargin = $bmargin;
1294 $this->orig_lMargin = $this->DeflMargin;
1295 $this->orig_rMargin = $this->DefrMargin;
1296 $this->orig_hMargin = $this->margin_header;
1297 $this->orig_fMargin = $this->margin_footer;
1298
1299 if ($this->setAutoTopMargin == 'pad') {
1300 $mgt += $this->margin_header;
1301 }
1302 if ($this->setAutoBottomMargin == 'pad') {
1303 $mgb += $this->margin_footer;
1304 }
1305
1306 // sets l r t margin
1307 $this->SetMargins($this->DeflMargin, $this->DefrMargin, $mgt);
1308
1309 // Automatic page break
1310 // sets $this->bMargin & PageBreakTrigger
1311 $this->SetAutoPageBreak($this->autoPageBreak, $bmargin);
1312
1313 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
1314
1315 // Interior cell margin (1 mm) ? not used
1316 $this->cMarginL = 1;
1317 $this->cMarginR = 1;
1318
1319 // Line width (0.2 mm)
1320 $this->LineWidth = .567 / Mpdf::SCALE;
1321
1322 // Enable all tags as default
1323 $this->DisableTags();
1324 // Full width display mode
1325 $this->SetDisplayMode(100); // fullwidth? 'fullpage'
1326
1327 // Compression
1328 $this->SetCompression(true);
1329 // Set default display preferences
1330 $this->SetDisplayPreferences('');
1331
1332 $this->initFontConfig($originalConfig);
1333
1334 // Available fonts
1335 $this->available_unifonts = [];
1336 foreach ($this->fontdata as $f => $fs) {
1337 if (isset($fs['R']) && $fs['R']) {
1338 $this->available_unifonts[] = $f;
1339 }
1340 if (isset($fs['B']) && $fs['B']) {
1341 $this->available_unifonts[] = $f . 'B';
1342 }
1343 if (isset($fs['I']) && $fs['I']) {
1344 $this->available_unifonts[] = $f . 'I';
1345 }
1346 if (isset($fs['BI']) && $fs['BI']) {
1347 $this->available_unifonts[] = $f . 'BI';
1348 }
1349 }
1350
1351 $this->default_available_fonts = $this->available_unifonts;
1352
1353 $optcore = false;
1354 $onlyCoreFonts = false;
1355 if (preg_match('/([\-+])aCJK/i', $mode, $m)) {
1356 $mode = preg_replace('/([\-+])aCJK/i', '', $mode); // mPDF 6
1357 if ($m[1] == '+') {
1358 $this->useAdobeCJK = true;
1359 } else {
1360 $this->useAdobeCJK = false;
1361 }
1362 }
1363
1364 if (strlen($mode) == 1) {
1365 if ($mode == 's') {
1366 $this->percentSubset = 100;
1367 $mode = '';
1368 } elseif ($mode == 'c') {
1369 $onlyCoreFonts = true;
1370 $mode = '';
1371 }
1372 } elseif (substr($mode, -2) == '-s') {
1373 $this->percentSubset = 100;
1374 $mode = substr($mode, 0, strlen($mode) - 2);
1375 } elseif (substr($mode, -2) == '-c') {
1376 $onlyCoreFonts = true;
1377 $mode = substr($mode, 0, strlen($mode) - 2);
1378 } elseif (substr($mode, -2) == '-x') {
1379 $optcore = true;
1380 $mode = substr($mode, 0, strlen($mode) - 2);
1381 }
1382
1383 // Autodetect if mode is a language_country string (en-GB or en_GB or en)
1384 if ($mode && $mode != 'UTF-8') { // mPDF 6
1385 list ($coreSuitable, $mpdf_pdf_unifont) = $this->languageToFont->getLanguageOptions($mode, $this->useAdobeCJK);
1386 if ($coreSuitable && $optcore) {
1387 $onlyCoreFonts = true;
1388 }
1389 if ($mpdf_pdf_unifont) { // mPDF 6
1390 $default_font = $mpdf_pdf_unifont;
1391 }
1392 $this->currentLang = $mode;
1393 $this->default_lang = $mode;
1394 }
1395
1396 $this->onlyCoreFonts = $onlyCoreFonts;
1397
1398 if ($this->onlyCoreFonts) {
1399 $this->setMBencoding('windows-1252'); // sets $this->mb_enc
1400 } else {
1401 $this->setMBencoding('UTF-8'); // sets $this->mb_enc
1402 }
1403 @mb_regex_encoding('UTF-8'); // required only for mb_ereg... and mb_split functions
1404
1405 // Adobe CJK fonts
1406 $this->available_CJK_fonts = [
1407 'gb',
1408 'big5',
1409 'sjis',
1410 'uhc',
1411 'gbB',
1412 'big5B',
1413 'sjisB',
1414 'uhcB',
1415 'gbI',
1416 'big5I',
1417 'sjisI',
1418 'uhcI',
1419 'gbBI',
1420 'big5BI',
1421 'sjisBI',
1422 'uhcBI',
1423 ];
1424
1425 // Standard fonts
1426 $this->CoreFonts = [
1427 'ccourier' => 'Courier',
1428 'ccourierB' => 'Courier-Bold',
1429 'ccourierI' => 'Courier-Oblique',
1430 'ccourierBI' => 'Courier-BoldOblique',
1431 'chelvetica' => 'Helvetica',
1432 'chelveticaB' => 'Helvetica-Bold',
1433 'chelveticaI' => 'Helvetica-Oblique',
1434 'chelveticaBI' => 'Helvetica-BoldOblique',
1435 'ctimes' => 'Times-Roman',
1436 'ctimesB' => 'Times-Bold',
1437 'ctimesI' => 'Times-Italic',
1438 'ctimesBI' => 'Times-BoldItalic',
1439 'csymbol' => 'Symbol',
1440 'czapfdingbats' => 'ZapfDingbats'
1441 ];
1442
1443 $this->fontlist = [
1444 "ctimes",
1445 "ccourier",
1446 "chelvetica",
1447 "csymbol",
1448 "czapfdingbats"
1449 ];
1450
1451 // Substitutions
1452 $this->setHiEntitySubstitutions();
1453
1454 if ($this->onlyCoreFonts) {
1455 $this->useSubstitutions = true;
1456 $this->SetSubstitutions();
1457 } else {
1458 $this->useSubstitutions = $config['useSubstitutions'];
1459 }
1460
1461 if (file_exists($this->defaultCssFile)) {
1462 $css = file_get_contents($this->defaultCssFile);
1463 $this->cssManager->ReadCSS('<style> ' . $css . ' </style>');
1464 } else {
1465 throw new \Mpdf\MpdfException(sprintf('Unable to read default CSS file "%s"', $this->defaultCssFile));
1466 }
1467
1468 if ($default_font == '') {
1469 if ($this->onlyCoreFonts) {
1470 if (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']), $this->mono_fonts)) {
1471 $default_font = 'ccourier';
1472 } elseif (in_array(strtolower($this->defaultCSS['BODY']['FONT-FAMILY']), $this->sans_fonts)) {
1473 $default_font = 'chelvetica';
1474 } else {
1475 $default_font = 'ctimes';
1476 }
1477 } else {
1478 $default_font = $this->defaultCSS['BODY']['FONT-FAMILY'];
1479 }
1480 }
1481 if (!$default_font_size) {
1482 $mmsize = $this->sizeConverter->convert($this->defaultCSS['BODY']['FONT-SIZE']);
1483 $default_font_size = $mmsize * (Mpdf::SCALE);
1484 }
1485
1486 if ($default_font) {
1487 $this->SetDefaultFont($default_font);
1488 }
1489 if ($default_font_size) {
1490 $this->SetDefaultFontSize($default_font_size);
1491 }
1492
1493 $this->SetLineHeight(); // lineheight is in mm
1494
1495 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
1496 $this->HREF = '';
1497 $this->oldy = -1;
1498 $this->B = 0;
1499 $this->I = 0;
1500
1501 // mPDF 6 Lists
1502 $this->listlvl = 0;
1503 $this->listtype = [];
1504 $this->listitem = [];
1505 $this->listcounter = [];
1506
1507 $this->tdbegin = false;
1508 $this->table = [];
1509 $this->cell = [];
1510 $this->col = -1;
1511 $this->row = -1;
1512 $this->cellBorderBuffer = [];
1513
1514 $this->divbegin = false;
1515 // mPDF 6
1516 $this->cellTextAlign = '';
1517 $this->cellLineHeight = '';
1518 $this->cellLineStackingStrategy = '';
1519 $this->cellLineStackingShift = '';
1520
1521 $this->divwidth = 0;
1522 $this->divheight = 0;
1523 $this->spanbgcolor = false;
1524 $this->spanborder = false;
1525 $this->spanborddet = [];
1526
1527 $this->blockjustfinished = false;
1528 $this->ignorefollowingspaces = true; // in order to eliminate exceeding left-side spaces
1529 $this->dash_on = false;
1530 $this->dotted_on = false;
1531 $this->textshadow = '';
1532
1533 $this->currentfontfamily = '';
1534 $this->currentfontsize = '';
1535 $this->currentfontstyle = '';
1536 $this->colorarray = ''; // mPDF 6
1537 $this->spanbgcolorarray = ''; // mPDF 6
1538 $this->textbuffer = [];
1539 $this->internallink = [];
1540 $this->basepath = "";
1541
1542 $this->SetBasePath('');
1543
1544 $this->textparam = [];
1545
1546 $this->specialcontent = '';
1547 $this->selectoption = [];
1548 }
1549
1550 public function cleanup()
1551 {
1552 mb_internal_encoding($this->originalMbEnc);
1553 @mb_regex_encoding($this->originalMbRegexEnc);
1554
1555 // this will free up the readers, based on code from Setasign's FpdiTrait::cleanUp()
1556 foreach ($this->createdReaders as $id) {
1557 $this->readers[$id]->getParser()->getStreamReader()->cleanUp();
1558 unset($this->readers[$id]);
1559 }
1560
1561 $this->createdReaders = [];
1562 }
1563
1569 public function setLogger(LoggerInterface $logger)
1570 {
1571 $this->logger = $logger;
1572
1573 foreach ($this->services as $name) {
1574 if ($this->$name && $this->$name instanceof \Psr\Log\LoggerAwareInterface) {
1575 $this->$name->setLogger($logger);
1576 }
1577 }
1578
1579 return $this;
1580 }
1581
1582 private function initConfig(array $config)
1583 {
1584 $configObject = new ConfigVariables();
1585 $defaults = $configObject->getDefaults();
1586 $config = array_intersect_key($config + $defaults, $defaults);
1587
1588 foreach ($config as $var => $val) {
1589 $this->{$var} = $val;
1590 }
1591
1592 return $config;
1593 }
1594
1595 private function initConstructorParams(array $config)
1596 {
1597 $constructor = [
1598 'mode' => '',
1599 'format' => 'A4',
1600 'default_font_size' => 0,
1601 'default_font' => '',
1602 'margin_left' => 15,
1603 'margin_right' => 15,
1604 'margin_top' => 16,
1605 'margin_bottom' => 16,
1606 'margin_header' => 9,
1607 'margin_footer' => 9,
1608 'orientation' => 'P',
1609 ];
1610
1611 foreach ($constructor as $key => $val) {
1612 if (isset($config[$key])) {
1613 $constructor[$key] = $config[$key];
1614 }
1615 }
1616
1617 return array_values($constructor);
1618 }
1619
1620 private function initFontConfig(array $config)
1621 {
1622 $configObject = new FontVariables();
1623 $defaults = $configObject->getDefaults();
1624 $config = array_intersect_key($config + $defaults, $defaults);
1625 foreach ($config as $var => $val) {
1626 $this->{$var} = $val;
1627 }
1628
1629 return $config;
1630 }
1631
1632 function _setPageSize($format, &$orientation)
1633 {
1634 if (is_string($format)) {
1635
1636 if (empty($format)) {
1637 $format = 'A4';
1638 }
1639
1640 // e.g. A4-L = A4 landscape, A4-P = A4 portrait
1641 if (preg_match('/([0-9a-zA-Z]*)-([P,L])/i', $format, $m)) {
1642 $format = $m[1];
1643 $orientation = $m[2];
1644 } elseif (empty($orientation)) {
1645 $orientation = 'P';
1646 }
1647
1648 $format = PageFormat::getSizeFromName($format);
1649
1650 $this->fwPt = $format[0];
1651 $this->fhPt = $format[1];
1652
1653 } else {
1654
1655 if (!$format[0] || !$format[1]) {
1656 throw new \Mpdf\MpdfException('Invalid page format: ' . $format[0] . ' ' . $format[1]);
1657 }
1658
1659 $this->fwPt = $format[0] * Mpdf::SCALE;
1660 $this->fhPt = $format[1] * Mpdf::SCALE;
1661 }
1662
1663 $this->fw = $this->fwPt / Mpdf::SCALE;
1664 $this->fh = $this->fhPt / Mpdf::SCALE;
1665
1666 // Page orientation
1667 $orientation = strtolower($orientation);
1668 if ($orientation === 'p' || $orientation == 'portrait') {
1669 $orientation = 'P';
1670 $this->wPt = $this->fwPt;
1671 $this->hPt = $this->fhPt;
1672 } elseif ($orientation === 'l' || $orientation == 'landscape') {
1673 $orientation = 'L';
1674 $this->wPt = $this->fhPt;
1675 $this->hPt = $this->fwPt;
1676 } else {
1677 throw new \Mpdf\MpdfException('Incorrect orientation: ' . $orientation);
1678 }
1679
1680 $this->CurOrientation = $orientation;
1681
1682 $this->w = $this->wPt / Mpdf::SCALE;
1683 $this->h = $this->hPt / Mpdf::SCALE;
1684 }
1685
1687 {
1688 // $res = array of (Unicode) fonts to restrict to: e.g. norasi|norasiB - language specific
1689 if (count($res)) { // Leave full list of available fonts if passed blank array
1690 $this->available_unifonts = $res;
1691 } else {
1692 $this->available_unifonts = $this->default_available_fonts;
1693 }
1694 if (count($this->available_unifonts) == 0) {
1695 $this->available_unifonts[] = $this->default_available_fonts[0];
1696 }
1697 $this->available_unifonts = array_values($this->available_unifonts);
1698 }
1699
1700 function setMBencoding($enc)
1701 {
1702 if ($this->mb_enc != $enc) {
1703 $this->mb_enc = $enc;
1704 mb_internal_encoding($this->mb_enc);
1705 }
1706 }
1707
1708 function SetMargins($left, $right, $top)
1709 {
1710 // Set left, top and right margins
1711 $this->lMargin = $left;
1712 $this->rMargin = $right;
1713 $this->tMargin = $top;
1714 }
1715
1716 function ResetMargins()
1717 {
1718 // ReSet left, top margins
1719 if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P' && $this->CurOrientation == 'L') {
1720 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
1721 $this->tMargin = $this->orig_rMargin;
1722 $this->bMargin = $this->orig_lMargin;
1723 } else { // ODD // OR NOT MIRRORING MARGINS/FOOTERS
1724 $this->tMargin = $this->orig_lMargin;
1725 $this->bMargin = $this->orig_rMargin;
1726 }
1727 $this->lMargin = $this->DeflMargin;
1728 $this->rMargin = $this->DefrMargin;
1729 $this->MarginCorrection = 0;
1730 $this->PageBreakTrigger = $this->h - $this->bMargin;
1731 } elseif (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
1732 $this->lMargin = $this->DefrMargin;
1733 $this->rMargin = $this->DeflMargin;
1734 $this->MarginCorrection = $this->DefrMargin - $this->DeflMargin;
1735 } else { // ODD // OR NOT MIRRORING MARGINS/FOOTERS
1736 $this->lMargin = $this->DeflMargin;
1737 $this->rMargin = $this->DefrMargin;
1738 if ($this->mirrorMargins) {
1739 $this->MarginCorrection = $this->DeflMargin - $this->DefrMargin;
1740 }
1741 }
1742 $this->x = $this->lMargin;
1743 }
1744
1745 function SetLeftMargin($margin)
1746 {
1747 // Set left margin
1748 $this->lMargin = $margin;
1749 if ($this->page > 0 and $this->x < $margin) {
1750 $this->x = $margin;
1751 }
1752 }
1753
1754 function SetTopMargin($margin)
1755 {
1756 // Set top margin
1757 $this->tMargin = $margin;
1758 }
1759
1760 function SetRightMargin($margin)
1761 {
1762 // Set right margin
1763 $this->rMargin = $margin;
1764 }
1765
1766 function SetAutoPageBreak($auto, $margin = 0)
1767 {
1768 // Set auto page break mode and triggering margin
1769 $this->autoPageBreak = $auto;
1770 $this->bMargin = $margin;
1771 $this->PageBreakTrigger = $this->h - $margin;
1772 }
1773
1774 function SetDisplayMode($zoom, $layout = 'continuous')
1775 {
1776 $allowedZoomModes = ['fullpage', 'fullwidth', 'real', 'default', 'none'];
1777
1778 if (in_array($zoom, $allowedZoomModes, true) || is_numeric($zoom)) {
1779 $this->ZoomMode = $zoom;
1780 } else {
1781 throw new \Mpdf\MpdfException('Incorrect zoom display mode: ' . $zoom);
1782 }
1783
1784 $allowedLayoutModes = ['single', 'continuous', 'two', 'twoleft', 'tworight', 'default'];
1785
1786 if (in_array($layout, $allowedLayoutModes, true)) {
1787 $this->LayoutMode = $layout;
1788 } else {
1789 throw new \Mpdf\MpdfException('Incorrect layout display mode: ' . $layout);
1790 }
1791 }
1792
1793 function SetCompression($compress)
1794 {
1795 // Set page compression
1796 if (function_exists('gzcompress')) {
1797 $this->compress = $compress;
1798 } else {
1799 $this->compress = false;
1800 }
1801 }
1802
1803 function SetTitle($title)
1804 {
1805 // Title of document // Arrives as UTF-8
1806 $this->title = $title;
1807 }
1808
1809 function SetSubject($subject)
1810 {
1811 // Subject of document
1812 $this->subject = $subject;
1813 }
1814
1815 function SetAuthor($author)
1816 {
1817 // Author of document
1818 $this->author = $author;
1819 }
1820
1821 function SetKeywords($keywords)
1822 {
1823 // Keywords of document
1824 $this->keywords = $keywords;
1825 }
1826
1827 function SetCreator($creator)
1828 {
1829 // Creator of document
1830 $this->creator = $creator;
1831 }
1832
1833 function AddCustomProperty($key, $value)
1834 {
1835 $this->customProperties[$key] = $value;
1836 }
1837
1861 function SetAssociatedFiles(array $files)
1862 {
1863 $this->associatedFiles = $files;
1864 }
1865
1867 {
1868 $this->additionalXmpRdf = $s;
1869 }
1870
1872 {
1873 $this->anchor2Bookmark = $x;
1874 }
1875
1876 public function AliasNbPages($alias = '{nb}')
1877 {
1878 // Define an alias for total number of pages
1879 $this->aliasNbPg = $alias;
1880 }
1881
1882 public function AliasNbPageGroups($alias = '{nbpg}')
1883 {
1884 // Define an alias for total number of pages in a group
1885 $this->aliasNbPgGp = $alias;
1886 }
1887
1888 function SetAlpha($alpha, $bm = 'Normal', $return = false, $mode = 'B')
1889 {
1890 // alpha: real value from 0 (transparent) to 1 (opaque)
1891 // bm: blend mode, one of the following:
1892 // Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn,
1893 // HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity
1894 // set alpha for stroking (CA) and non-stroking (ca) operations
1895 // mode determines F (fill) S (stroke) B (both)
1896 if (($this->PDFA || $this->PDFX) && $alpha != 1) {
1897 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
1898 $this->PDFAXwarnings[] = "Image opacity must be 100% (Opacity changed to 100%)";
1899 }
1900 $alpha = 1;
1901 }
1902 $a = ['BM' => '/' . $bm];
1903 if ($mode == 'F' || $mode == 'B') {
1904 $a['ca'] = $alpha; // mPDF 5.7.2
1905 }
1906 if ($mode == 'S' || $mode == 'B') {
1907 $a['CA'] = $alpha; // mPDF 5.7.2
1908 }
1909 $gs = $this->AddExtGState($a);
1910 if ($return) {
1911 return sprintf('/GS%d gs', $gs);
1912 } else {
1913 $this->writer->write(sprintf('/GS%d gs', $gs));
1914 }
1915 }
1916
1917 function AddExtGState($parms)
1918 {
1919 $n = count($this->extgstates);
1920 // check if graphics state already exists
1921 for ($i = 1; $i <= $n; $i++) {
1922 if (count($this->extgstates[$i]['parms']) == count($parms)) {
1923 $same = true;
1924 foreach ($this->extgstates[$i]['parms'] as $k => $v) {
1925 if (!isset($parms[$k]) || $parms[$k] != $v) {
1926 $same = false;
1927 break;
1928 }
1929 }
1930 if ($same) {
1931 return $i;
1932 }
1933 }
1934 }
1935 $n++;
1936 $this->extgstates[$n]['parms'] = $parms;
1937 return $n;
1938 }
1939
1940 function SetVisibility($v)
1941 {
1942 if (($this->PDFA || $this->PDFX) && $this->visibility != 'visible') {
1943 $this->PDFAXwarnings[] = "Cannot set visibility to anything other than full when using PDFA or PDFX";
1944 return '';
1945 } elseif (!$this->PDFA && !$this->PDFX) {
1946 $this->pdf_version = '1.5';
1947 }
1948 if ($this->visibility != 'visible') {
1949 $this->writer->write('EMC');
1950 $this->hasOC = intval($this->hasOC);
1951 }
1952 if ($v == 'printonly') {
1953 $this->writer->write('/OC /OC1 BDC');
1954 $this->hasOC = ($this->hasOC | 1);
1955 } elseif ($v == 'screenonly') {
1956 $this->writer->write('/OC /OC2 BDC');
1957 $this->hasOC = ($this->hasOC | 2);
1958 } elseif ($v == 'hidden') {
1959 $this->writer->write('/OC /OC3 BDC');
1960 $this->hasOC = ($this->hasOC | 4);
1961 } elseif ($v != 'visible') {
1962 throw new \Mpdf\MpdfException('Incorrect visibility: ' . $v);
1963 }
1964 $this->visibility = $v;
1965 }
1966
1967 function Open()
1968 {
1969 // Begin document
1970 if ($this->state == 0) {
1971 $this->state = 1;
1972 if (false === $this->preambleWritten) {
1973 $this->writer->write('%PDF-' . $this->pdf_version);
1974 $this->writer->write('%' . chr(226) . chr(227) . chr(207) . chr(211)); // 4 chars > 128 to show binary file
1975 $this->preambleWritten = true;
1976 }
1977 }
1978 }
1979
1980 function Close()
1981 {
1982 // @log Closing last page
1983
1984 // Terminate document
1985 if ($this->state == 3) {
1986 return;
1987 }
1988
1989 if ($this->page == 0) {
1990 $this->AddPage($this->CurOrientation);
1991 }
1992
1993 if (count($this->cellBorderBuffer)) {
1994 $this->printcellbuffer();
1995 }
1996
1997 // *TABLES*
1998 if ($this->tablebuffer) {
1999 $this->printtablebuffer();
2000 }
2001
2002 /* -- COLUMNS -- */
2003
2004 if ($this->ColActive) {
2005 $this->SetColumns(0);
2006 $this->ColActive = 0;
2007 if (count($this->columnbuffer)) {
2008 $this->printcolumnbuffer();
2009 }
2010 }
2011
2012 /* -- END COLUMNS -- */
2013
2014 // BODY Backgrounds
2015 $s = '';
2016
2017 $s .= $this->PrintBodyBackgrounds();
2018 $s .= $this->PrintPageBackgrounds();
2019
2020 $this->pages[$this->page] = preg_replace(
2021 '/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/',
2022 "\n" . $s . "\n" . '\\1',
2023 $this->pages[$this->page]
2024 );
2025
2026 $this->pageBackgrounds = [];
2027
2028 if ($this->visibility != 'visible') {
2029 $this->SetVisibility('visible');
2030 }
2031
2032 $this->EndLayer();
2033
2034 if (!$this->tableOfContents->TOCmark) { // Page footer
2035 $this->InFooter = true;
2036 $this->Footer();
2037 $this->InFooter = false;
2038 }
2039
2040 if ($this->tableOfContents->TOCmark || count($this->tableOfContents->m_TOC)) {
2041 $this->tableOfContents->insertTOC();
2042 }
2043
2044 // Close page
2045 $this->_endpage();
2046
2047 // Close document
2048 $this->_enddoc();
2049 }
2050
2051 /* -- BACKGROUNDS -- */
2052
2053 function _resizeBackgroundImage($imw, $imh, $cw, $ch, $resize, $repx, $repy, $pba = [], $size = [])
2054 {
2055 // pba is background positioning area (from CSS background-origin) may not always be set [x,y,w,h]
2056 // size is from CSS3 background-size - takes precendence over old resize
2057 // $w - absolute length or % or auto or cover | contain
2058 // $h - absolute length or % or auto or cover | contain
2059 if (isset($pba['w'])) {
2060 $cw = $pba['w'];
2061 }
2062 if (isset($pba['h'])) {
2063 $ch = $pba['h'];
2064 }
2065
2066 $cw = $cw * Mpdf::SCALE;
2067 $ch = $ch * Mpdf::SCALE;
2068 if (empty($size) && !$resize) {
2069 return [$imw, $imh, $repx, $repy];
2070 }
2071
2072 if (isset($size['w']) && $size['w']) {
2073 if ($size['w'] == 'contain') {
2074 // Scale the image, while preserving its intrinsic aspect ratio (if any),
2075 // to the largest size such that both its width and its height can fit inside the background positioning area.
2076 // Same as resize==3
2077 $h = $imh * $cw / $imw;
2078 $w = $cw;
2079 if ($h > $ch) {
2080 $w = $w * $ch / $h;
2081 $h = $ch;
2082 }
2083 } elseif ($size['w'] == 'cover') {
2084 // Scale the image, while preserving its intrinsic aspect ratio (if any),
2085 // to the smallest size such that both its width and its height can completely cover the background positioning area.
2086 $h = $imh * $cw / $imw;
2087 $w = $cw;
2088 if ($h < $ch) {
2089 $w = $w * $h / $ch;
2090 $h = $ch;
2091 }
2092 } else {
2093 if (stristr($size['w'], '%')) {
2094 $size['w'] = (float) $size['w'];
2095 $size['w'] /= 100;
2096 $size['w'] = ($cw * $size['w']);
2097 }
2098 if (stristr($size['h'], '%')) {
2099 $size['h'] = (float) $size['h'];
2100 $size['h'] /= 100;
2101 $size['h'] = ($ch * $size['h']);
2102 }
2103 if ($size['w'] == 'auto' && $size['h'] == 'auto') {
2104 $w = $imw;
2105 $h = $imh;
2106 } elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
2107 $w = $imw * $size['h'] / $imh;
2108 $h = $size['h'];
2109 } elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
2110 $h = $imh * $size['w'] / $imw;
2111 $w = $size['w'];
2112 } else {
2113 $w = $size['w'];
2114 $h = $size['h'];
2115 }
2116 }
2117 return [$w, $h, $repx, $repy];
2118 } elseif ($resize == 1 && $imw > $cw) {
2119 $h = $imh * $cw / $imw;
2120 return [$cw, $h, $repx, $repy];
2121 } elseif ($resize == 2 && $imh > $ch) {
2122 $w = $imw * $ch / $imh;
2123 return [$w, $ch, $repx, $repy];
2124 } elseif ($resize == 3) {
2125 $w = $imw;
2126 $h = $imh;
2127 if ($w > $cw) {
2128 $h = $h * $cw / $w;
2129 $w = $cw;
2130 }
2131 if ($h > $ch) {
2132 $w = $w * $ch / $h;
2133 $h = $ch;
2134 }
2135 return [$w, $h, $repx, $repy];
2136 } elseif ($resize == 4) {
2137 $h = $imh * $cw / $imw;
2138 return [$cw, $h, $repx, $repy];
2139 } elseif ($resize == 5) {
2140 $w = $imw * $ch / $imh;
2141 return [$w, $ch, $repx, $repy];
2142 } elseif ($resize == 6) {
2143 return [$cw, $ch, $repx, $repy];
2144 }
2145 return [$imw, $imh, $repx, $repy];
2146 }
2147
2148 function SetBackground(&$properties, &$maxwidth)
2149 {
2150 if (isset($properties['BACKGROUND-ORIGIN']) && ($properties['BACKGROUND-ORIGIN'] == 'border-box' || $properties['BACKGROUND-ORIGIN'] == 'content-box')) {
2151 $origin = $properties['BACKGROUND-ORIGIN'];
2152 } else {
2153 $origin = 'padding-box';
2154 }
2155
2156 if (isset($properties['BACKGROUND-SIZE'])) {
2157 if (stristr($properties['BACKGROUND-SIZE'], 'contain')) {
2158 $bsw = $bsh = 'contain';
2159 } elseif (stristr($properties['BACKGROUND-SIZE'], 'cover')) {
2160 $bsw = $bsh = 'cover';
2161 } else {
2162 $bsw = $bsh = 'auto';
2163 $sz = preg_split('/\s+/', trim($properties['BACKGROUND-SIZE']));
2164 if (count($sz) == 2) {
2165 $bsw = $sz[0];
2166 $bsh = $sz[1];
2167 } else {
2168 $bsw = $sz[0];
2169 }
2170 if (!stristr($bsw, '%') && !stristr($bsw, 'auto')) {
2171 $bsw = $this->sizeConverter->convert($bsw, $maxwidth, $this->FontSize);
2172 }
2173 if (!stristr($bsh, '%') && !stristr($bsh, 'auto')) {
2174 $bsh = $this->sizeConverter->convert($bsh, $maxwidth, $this->FontSize);
2175 }
2176 }
2177 $size = ['w' => $bsw, 'h' => $bsh];
2178 } else {
2179 $size = false;
2180 } // mPDF 6
2181 if (preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $properties['BACKGROUND-IMAGE'])) {
2182 return ['gradient' => $properties['BACKGROUND-IMAGE'], 'origin' => $origin, 'size' => $size];
2183 } else {
2184 $file = $properties['BACKGROUND-IMAGE'];
2185 $sizesarray = $this->Image($file, 0, 0, 0, 0, '', '', false, false, false, false, true);
2186 if (isset($sizesarray['IMAGE_ID'])) {
2187 $image_id = $sizesarray['IMAGE_ID'];
2188 $orig_w = $sizesarray['WIDTH'] * Mpdf::SCALE; // in user units i.e. mm
2189 $orig_h = $sizesarray['HEIGHT'] * Mpdf::SCALE; // (using $this->img_dpi)
2190 if (isset($properties['BACKGROUND-IMAGE-RESOLUTION'])) {
2191 if (preg_match('/from-image/i', $properties['BACKGROUND-IMAGE-RESOLUTION']) && isset($sizesarray['set-dpi']) && $sizesarray['set-dpi'] > 0) {
2192 $orig_w *= $this->img_dpi / $sizesarray['set-dpi'];
2193 $orig_h *= $this->img_dpi / $sizesarray['set-dpi'];
2194 } elseif (preg_match('/(\d+)dpi/i', $properties['BACKGROUND-IMAGE-RESOLUTION'], $m)) {
2195 $dpi = $m[1];
2196 if ($dpi > 0) {
2197 $orig_w *= $this->img_dpi / $dpi;
2198 $orig_h *= $this->img_dpi / $dpi;
2199 }
2200 }
2201 }
2202 $x_repeat = true;
2203 $y_repeat = true;
2204 if (isset($properties['BACKGROUND-REPEAT'])) {
2205 if ($properties['BACKGROUND-REPEAT'] == 'no-repeat' || $properties['BACKGROUND-REPEAT'] == 'repeat-x') {
2206 $y_repeat = false;
2207 }
2208 if ($properties['BACKGROUND-REPEAT'] == 'no-repeat' || $properties['BACKGROUND-REPEAT'] == 'repeat-y') {
2209 $x_repeat = false;
2210 }
2211 }
2212 $x_pos = 0;
2213 $y_pos = 0;
2214 if (isset($properties['BACKGROUND-POSITION'])) {
2215 $ppos = preg_split('/\s+/', $properties['BACKGROUND-POSITION']);
2216 $x_pos = $ppos[0];
2217 $y_pos = $ppos[1];
2218 if (!stristr($x_pos, '%')) {
2219 $x_pos = $this->sizeConverter->convert($x_pos, $maxwidth, $this->FontSize);
2220 }
2221 if (!stristr($y_pos, '%')) {
2222 $y_pos = $this->sizeConverter->convert($y_pos, $maxwidth, $this->FontSize);
2223 }
2224 }
2225 if (isset($properties['BACKGROUND-IMAGE-RESIZE'])) {
2226 $resize = $properties['BACKGROUND-IMAGE-RESIZE'];
2227 } else {
2228 $resize = 0;
2229 }
2230 if (isset($properties['BACKGROUND-IMAGE-OPACITY'])) {
2231 $opacity = $properties['BACKGROUND-IMAGE-OPACITY'];
2232 } else {
2233 $opacity = 1;
2234 }
2235 return ['image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'resize' => $resize, 'opacity' => $opacity, 'itype' => $sizesarray['itype'], 'origin' => $origin, 'size' => $size];
2236 }
2237 }
2238 return false;
2239 }
2240
2241 /* -- END BACKGROUNDS -- */
2242
2244 {
2245 $s = '';
2246 $clx = 0;
2247 $cly = 0;
2248 $clw = $this->w;
2249 $clh = $this->h;
2250 // If using bleed and trim margins in paged media
2251 if ($this->pageDim[$this->page]['outer_width_LR'] || $this->pageDim[$this->page]['outer_width_TB']) {
2252 $clx = $this->pageDim[$this->page]['outer_width_LR'] - $this->pageDim[$this->page]['bleedMargin'];
2253 $cly = $this->pageDim[$this->page]['outer_width_TB'] - $this->pageDim[$this->page]['bleedMargin'];
2254 $clw = $this->w - 2 * $clx;
2255 $clh = $this->h - 2 * $cly;
2256 }
2257
2258 if ($this->bodyBackgroundColor) {
2259 $s .= 'q ' . $this->SetFColor($this->bodyBackgroundColor, true) . "\n";
2260 if ($this->bodyBackgroundColor[0] == 5) { // RGBa
2261 $s .= $this->SetAlpha(ord($this->bodyBackgroundColor[4]) / 100, 'Normal', true, 'F') . "\n";
2262 } elseif ($this->bodyBackgroundColor[0] == 6) { // CMYKa
2263 $s .= $this->SetAlpha(ord($this->bodyBackgroundColor[5]) / 100, 'Normal', true, 'F') . "\n";
2264 }
2265 $s .= sprintf('%.3F %.3F %.3F %.3F re f Q', ($clx * Mpdf::SCALE), ($cly * Mpdf::SCALE), $clw * Mpdf::SCALE, $clh * Mpdf::SCALE) . "\n";
2266 }
2267
2268 /* -- BACKGROUNDS -- */
2269 if ($this->bodyBackgroundGradient) {
2270 $g = $this->gradient->parseBackgroundGradient($this->bodyBackgroundGradient);
2271 if ($g) {
2272 $s .= $this->gradient->Gradient($clx, $cly, $clw, $clh, (isset($g['gradtype']) ? $g['gradtype'] : null), $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true);
2273 }
2274 }
2275 if ($this->bodyBackgroundImage) {
2276 if (isset($this->bodyBackgroundImage['gradient']) && $this->bodyBackgroundImage['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $this->bodyBackgroundImage['gradient'])) {
2277 $g = $this->gradient->parseMozGradient($this->bodyBackgroundImage['gradient']);
2278 if ($g) {
2279 $s .= $this->gradient->Gradient($clx, $cly, $clw, $clh, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true);
2280 }
2281 } elseif ($this->bodyBackgroundImage['image_id']) { // Background pattern
2282 $n = count($this->patterns) + 1;
2283 // If using resize, uses TrimBox (not including the bleed)
2284 list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($this->bodyBackgroundImage['orig_w'], $this->bodyBackgroundImage['orig_h'], $clw, $clh, $this->bodyBackgroundImage['resize'], $this->bodyBackgroundImage['x_repeat'], $this->bodyBackgroundImage['y_repeat']);
2285
2286 $this->patterns[$n] = ['x' => $clx, 'y' => $cly, 'w' => $clw, 'h' => $clh, 'pgh' => $this->h, 'image_id' => $this->bodyBackgroundImage['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $this->bodyBackgroundImage['x_pos'], 'y_pos' => $this->bodyBackgroundImage['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'itype' => $this->bodyBackgroundImage['itype']];
2287 if (($this->bodyBackgroundImage['opacity'] > 0 || $this->bodyBackgroundImage['opacity'] === '0') && $this->bodyBackgroundImage['opacity'] < 1) {
2288 $opac = $this->SetAlpha($this->bodyBackgroundImage['opacity'], 'Normal', true);
2289 } else {
2290 $opac = '';
2291 }
2292 $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, ($clx * Mpdf::SCALE), ($cly * Mpdf::SCALE), $clw * Mpdf::SCALE, $clh * Mpdf::SCALE) . "\n";
2293 }
2294 }
2295 /* -- END BACKGROUNDS -- */
2296 return $s;
2297 }
2298
2299 function _setClippingPath($clx, $cly, $clw, $clh)
2300 {
2301 $s = ' q 0 w '; // Line width=0
2302 $s .= sprintf('%.3F %.3F m ', ($clx) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // start point TL before the arc
2303 $s .= sprintf('%.3F %.3F l ', ($clx) * Mpdf::SCALE, ($this->h - ($cly + $clh)) * Mpdf::SCALE); // line to BL
2304 $s .= sprintf('%.3F %.3F l ', ($clx + $clw) * Mpdf::SCALE, ($this->h - ($cly + $clh)) * Mpdf::SCALE); // line to BR
2305 $s .= sprintf('%.3F %.3F l ', ($clx + $clw) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // line to TR
2306 $s .= sprintf('%.3F %.3F l ', ($clx) * Mpdf::SCALE, ($this->h - ($cly)) * Mpdf::SCALE); // line to TL
2307 $s .= ' W n '; // Ends path no-op & Sets the clipping path
2308 return $s;
2309 }
2310
2311 function PrintPageBackgrounds($adjustmenty = 0)
2312 {
2313 $s = '';
2314
2315 ksort($this->pageBackgrounds);
2316
2317 foreach ($this->pageBackgrounds as $bl => $pbs) {
2318
2319 foreach ($pbs as $pb) {
2320
2321 if ((!isset($pb['image_id']) && !isset($pb['gradient'])) || isset($pb['shadowonly'])) { // Background colour or boxshadow
2322
2323 if ($pb['z-index'] > 0) {
2324 $this->current_layer = $pb['z-index'];
2325 $s .= "\n" . '/OCBZ-index /ZI' . $pb['z-index'] . ' BDC' . "\n";
2326 }
2327
2328 if ($pb['visibility'] != 'visible') {
2329 if ($pb['visibility'] == 'printonly') {
2330 $s .= '/OC /OC1 BDC' . "\n";
2331 } elseif ($pb['visibility'] == 'screenonly') {
2332 $s .= '/OC /OC2 BDC' . "\n";
2333 } elseif ($pb['visibility'] == 'hidden') {
2334 $s .= '/OC /OC3 BDC' . "\n";
2335 }
2336 }
2337
2338 // Box shadow
2339 if (isset($pb['shadow']) && $pb['shadow']) {
2340 $s .= $pb['shadow'] . "\n";
2341 }
2342
2343 if (isset($pb['clippath']) && $pb['clippath']) {
2344 $s .= $pb['clippath'] . "\n";
2345 }
2346
2347 $s .= 'q ' . $this->SetFColor($pb['col'], true) . "\n";
2348
2349 if ($pb['col'] && $pb['col'][0] === '5') { // RGBa
2350 $s .= $this->SetAlpha(ord($pb['col'][4]) / 100, 'Normal', true, 'F') . "\n";
2351 } elseif ($pb['col'] && $pb['col'][0] === '6') { // CMYKa
2352 $s .= $this->SetAlpha(ord($pb['col'][5]) / 100, 'Normal', true, 'F') . "\n";
2353 }
2354
2355 $s .= sprintf('%.3F %.3F %.3F %.3F re f Q', $pb['x'] * Mpdf::SCALE, ($this->h - $pb['y']) * Mpdf::SCALE, $pb['w'] * Mpdf::SCALE, -$pb['h'] * Mpdf::SCALE) . "\n";
2356
2357 if (isset($pb['clippath']) && $pb['clippath']) {
2358 $s .= 'Q' . "\n";
2359 }
2360
2361 if ($pb['visibility'] != 'visible') {
2362 $s .= 'EMC' . "\n";
2363 }
2364
2365 if ($pb['z-index'] > 0) {
2366 $s .= "\n" . 'EMCBZ-index' . "\n";
2367 $this->current_layer = 0;
2368 }
2369 }
2370 }
2371
2372 /* -- BACKGROUNDS -- */
2373 foreach ($pbs as $pb) {
2374
2375 if ((isset($pb['gradient']) && $pb['gradient']) || (isset($pb['image_id']) && $pb['image_id'])) {
2376
2377 if ($pb['z-index'] > 0) {
2378 $this->current_layer = $pb['z-index'];
2379 $s .= "\n" . '/OCGZ-index /ZI' . $pb['z-index'] . ' BDC' . "\n";
2380 }
2381
2382 if ($pb['visibility'] != 'visible') {
2383 if ($pb['visibility'] == 'printonly') {
2384 $s .= '/OC /OC1 BDC' . "\n";
2385 } elseif ($pb['visibility'] == 'screenonly') {
2386 $s .= '/OC /OC2 BDC' . "\n";
2387 } elseif ($pb['visibility'] == 'hidden') {
2388 $s .= '/OC /OC3 BDC' . "\n";
2389 }
2390 }
2391
2392 }
2393
2394 if (isset($pb['gradient']) && $pb['gradient']) {
2395
2396 if (isset($pb['clippath']) && $pb['clippath']) {
2397 $s .= $pb['clippath'] . "\n";
2398 }
2399
2400 $s .= $this->gradient->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true);
2401
2402 if (isset($pb['clippath']) && $pb['clippath']) {
2403 $s .= 'Q' . "\n";
2404 }
2405
2406 } elseif (isset($pb['image_id']) && $pb['image_id']) { // Background Image
2407
2408 $pb['y'] -= $adjustmenty;
2409 $pb['h'] += $adjustmenty;
2410 $n = count($this->patterns) + 1;
2411
2412 list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($pb['orig_w'], $pb['orig_h'], $pb['w'], $pb['h'], $pb['resize'], $pb['x_repeat'], $pb['y_repeat'], $pb['bpa'], $pb['size']);
2413
2414 $this->patterns[$n] = ['x' => $pb['x'], 'y' => $pb['y'], 'w' => $pb['w'], 'h' => $pb['h'], 'pgh' => $this->h, 'image_id' => $pb['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $pb['x_pos'], 'y_pos' => $pb['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'itype' => $pb['itype'], 'bpa' => $pb['bpa']];
2415
2416 $x = $pb['x'] * Mpdf::SCALE;
2417 $y = ($this->h - $pb['y']) * Mpdf::SCALE;
2418 $w = $pb['w'] * Mpdf::SCALE;
2419 $h = -$pb['h'] * Mpdf::SCALE;
2420
2421 if (isset($pb['clippath']) && $pb['clippath']) {
2422 $s .= $pb['clippath'] . "\n";
2423 }
2424
2425 if ($this->writingHTMLfooter || $this->writingHTMLheader) { // Write each (tiles) image rather than use as a pattern
2426
2427 $iw = $pb['orig_w'] / Mpdf::SCALE;
2428 $ih = $pb['orig_h'] / Mpdf::SCALE;
2429
2430 $w = $pb['w'];
2431 $h = $pb['h'];
2432 $x0 = $pb['x'];
2433 $y0 = $pb['y'];
2434
2435 if (isset($pb['bpa']) && $pb['bpa']) {
2436 $w = $pb['bpa']['w'];
2437 $h = $pb['bpa']['h'];
2438 $x0 = $pb['bpa']['x'];
2439 $y0 = $pb['bpa']['y'];
2440 }
2441
2442 if (isset($pb['size']['w']) && $pb['size']['w']) {
2443 $size = $pb['size'];
2444
2445 if ($size['w'] == 'contain') {
2446 // Scale the image, while preserving its intrinsic aspect ratio (if any), to the largest
2447 // size such that both its width and its height can fit inside the background positioning area.
2448 // Same as resize==3
2449 $ih = $ih * $pb['bpa']['w'] / $iw;
2450 $iw = $pb['bpa']['w'];
2451 if ($ih > $pb['bpa']['h']) {
2452 $iw = $iw * $pb['bpa']['h'] / $ih;
2453 $ih = $pb['bpa']['h'];
2454 }
2455 } elseif ($size['w'] == 'cover') {
2456 // Scale the image, while preserving its intrinsic aspect ratio (if any), to the smallest
2457 // size such that both its width and its height can completely cover the background positioning area.
2458 $ih = $ih * $pb['bpa']['w'] / $iw;
2459 $iw = $pb['bpa']['w'];
2460 if ($ih < $pb['bpa']['h']) {
2461 $iw = $iw * $ih / $pb['bpa']['h'];
2462 $ih = $pb['bpa']['h'];
2463 }
2464 } else {
2465
2466 if (NumericString::containsPercentChar($size['w'])) {
2467 $size['w'] = NumericString::removePercentChar($size['w']);
2468 $size['w'] /= 100;
2469 $size['w'] = ($pb['bpa']['w'] * $size['w']);
2470 }
2471
2472 if (NumericString::containsPercentChar($size['h'])) {
2473 $size['h'] = NumericString::removePercentChar($size['h']);
2474 $size['h'] /= 100;
2475 $size['h'] = ($pb['bpa']['h'] * $size['h']);
2476 }
2477
2478 if ($size['w'] == 'auto' && $size['h'] == 'auto') {
2479 $iw = $iw;
2480 $ih = $ih;
2481 } elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
2482 $iw = $iw * $size['h'] / $ih;
2483 $ih = $size['h'];
2484 } elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
2485 $ih = $ih * $size['w'] / $iw;
2486 $iw = $size['w'];
2487 } else {
2488 $iw = $size['w'];
2489 $ih = $size['h'];
2490 }
2491 }
2492 }
2493
2494 // Number to repeat
2495 if ($pb['x_repeat']) {
2496 $nx = ceil($pb['w'] / $iw) + 1;
2497 } else {
2498 $nx = 1;
2499 }
2500
2501 if ($pb['y_repeat']) {
2502 $ny = ceil($pb['h'] / $ih) + 1;
2503 } else {
2504 $ny = 1;
2505 }
2506
2507 $x_pos = $pb['x_pos'];
2508 if (stristr($x_pos, '%')) {
2509 $x_pos = (float) $x_pos;
2510 $x_pos /= 100;
2511 $x_pos = ($pb['bpa']['w'] * $x_pos) - ($iw * $x_pos);
2512 }
2513
2514 $y_pos = $pb['y_pos'];
2515
2516 if (stristr($y_pos, '%')) {
2517 $y_pos = (float) $y_pos;
2518 $y_pos /= 100;
2519 $y_pos = ($pb['bpa']['h'] * $y_pos) - ($ih * $y_pos);
2520 }
2521
2522 if ($nx > 1) {
2523 while ($x_pos > ($pb['x'] - $pb['bpa']['x'])) {
2524 $x_pos -= $iw;
2525 }
2526 }
2527
2528 if ($ny > 1) {
2529 while ($y_pos > ($pb['y'] - $pb['bpa']['y'])) {
2530 $y_pos -= $ih;
2531 }
2532 }
2533
2534 for ($xi = 0; $xi < $nx; $xi++) {
2535 for ($yi = 0; $yi < $ny; $yi++) {
2536 $x = $x0 + $x_pos + ($iw * $xi);
2537 $y = $y0 + $y_pos + ($ih * $yi);
2538 if ($pb['opacity'] > 0 && $pb['opacity'] < 1) {
2539 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2540 } else {
2541 $opac = '';
2542 }
2543 $s .= sprintf("q %s %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $opac, $iw * Mpdf::SCALE, $ih * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($y + $ih)) * Mpdf::SCALE, $pb['image_id']) . "\n";
2544 }
2545 }
2546
2547 } else {
2548 if (($pb['opacity'] > 0 || $pb['opacity'] === '0') && $pb['opacity'] < 1) {
2549 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2550 } else {
2551 $opac = '';
2552 }
2553 $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) . "\n";
2554 }
2555
2556 if (isset($pb['clippath']) && $pb['clippath']) {
2557 $s .= 'Q' . "\n";
2558 }
2559 }
2560
2561 if ((isset($pb['gradient']) && $pb['gradient']) || (isset($pb['image_id']) && $pb['image_id'])) {
2562 if ($pb['visibility'] != 'visible') {
2563 $s .= 'EMC' . "\n";
2564 }
2565
2566 if ($pb['z-index'] > 0) {
2567 $s .= "\n" . 'EMCGZ-index' . "\n";
2568 $this->current_layer = 0;
2569 }
2570 }
2571 }
2572 /* -- END BACKGROUNDS -- */
2573 }
2574
2575 return $s;
2576 }
2577
2578 function PrintTableBackgrounds($adjustmenty = 0)
2579 {
2580 $s = '';
2581 /* -- BACKGROUNDS -- */
2582 ksort($this->tableBackgrounds);
2583 foreach ($this->tableBackgrounds as $bl => $pbs) {
2584 foreach ($pbs as $pb) {
2585 if ((!isset($pb['gradient']) || !$pb['gradient']) && (!isset($pb['image_id']) || !$pb['image_id'])) {
2586 $s .= 'q ' . $this->SetFColor($pb['col'], true) . "\n";
2587 if ($pb['col'][0] == 5) { // RGBa
2588 $s .= $this->SetAlpha(ord($pb['col'][4]) / 100, 'Normal', true, 'F') . "\n";
2589 } elseif ($pb['col'][0] == 6) { // CMYKa
2590 $s .= $this->SetAlpha(ord($pb['col'][5]) / 100, 'Normal', true, 'F') . "\n";
2591 }
2592 $s .= sprintf('%.3F %.3F %.3F %.3F re %s Q', $pb['x'] * Mpdf::SCALE, ($this->h - $pb['y']) * Mpdf::SCALE, $pb['w'] * Mpdf::SCALE, -$pb['h'] * Mpdf::SCALE, 'f') . "\n";
2593 }
2594 if (isset($pb['gradient']) && $pb['gradient']) {
2595 if (isset($pb['clippath']) && $pb['clippath']) {
2596 $s .= $pb['clippath'] . "\n";
2597 }
2598 $s .= $this->gradient->Gradient($pb['x'], $pb['y'], $pb['w'], $pb['h'], $pb['gradtype'], $pb['stops'], $pb['colorspace'], $pb['coords'], $pb['extend'], true);
2599 if (isset($pb['clippath']) && $pb['clippath']) {
2600 $s .= 'Q' . "\n";
2601 }
2602 }
2603 if (isset($pb['image_id']) && $pb['image_id']) { // Background pattern
2604 $pb['y'] -= $adjustmenty;
2605 $pb['h'] += $adjustmenty;
2606 $n = count($this->patterns) + 1;
2607 list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($pb['orig_w'], $pb['orig_h'], $pb['w'], $pb['h'], $pb['resize'], $pb['x_repeat'], $pb['y_repeat']);
2608 $this->patterns[$n] = ['x' => $pb['x'], 'y' => $pb['y'], 'w' => $pb['w'], 'h' => $pb['h'], 'pgh' => $this->h, 'image_id' => $pb['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $pb['x_pos'], 'y_pos' => $pb['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'itype' => $pb['itype']];
2609 $x = $pb['x'] * Mpdf::SCALE;
2610 $y = ($this->h - $pb['y']) * Mpdf::SCALE;
2611 $w = $pb['w'] * Mpdf::SCALE;
2612 $h = -$pb['h'] * Mpdf::SCALE;
2613
2614 // mPDF 5.7.3
2615 if (($this->writingHTMLfooter || $this->writingHTMLheader) && (!isset($pb['clippath']) || $pb['clippath'] == '')) {
2616 // Set clipping path
2617 $pb['clippath'] = sprintf(' q 0 w %.3F %.3F m %.3F %.3F l %.3F %.3F l %.3F %.3F l %.3F %.3F l W n ', $x, $y, $x, $y + $h, $x + $w, $y + $h, $x + $w, $y, $x, $y);
2618 }
2619
2620 if (isset($pb['clippath']) && $pb['clippath']) {
2621 $s .= $pb['clippath'] . "\n";
2622 }
2623
2624 // mPDF 5.7.3
2625 if ($this->writingHTMLfooter || $this->writingHTMLheader) { // Write each (tiles) image rather than use as a pattern
2626 $iw = $pb['orig_w'] / Mpdf::SCALE;
2627 $ih = $pb['orig_h'] / Mpdf::SCALE;
2628
2629 $w = $pb['w'];
2630 $h = $pb['h'];
2631 $x0 = $pb['x'];
2632 $y0 = $pb['y'];
2633
2634 if (isset($pb['bpa']) && $pb['bpa']) {
2635 $w = $pb['bpa']['w'];
2636 $h = $pb['bpa']['h'];
2637 $x0 = $pb['bpa']['x'];
2638 $y0 = $pb['bpa']['y'];
2639 } // At present 'bpa' (background page area) is not set for tablebackgrounds - only pagebackgrounds
2640 // For now, just set it as:
2641 else {
2642 $pb['bpa'] = ['x' => $x0, 'y' => $y0, 'w' => $w, 'h' => $h];
2643 }
2644
2645 if (isset($pb['size']['w']) && $pb['size']['w']) {
2646 $size = $pb['size'];
2647
2648 if ($size['w'] == 'contain') {
2649 // Scale the image, while preserving its intrinsic aspect ratio (if any), to the largest size such that both its width and its height can fit inside the background positioning area.
2650 // Same as resize==3
2651 $ih = $ih * $pb['bpa']['w'] / $iw;
2652 $iw = $pb['bpa']['w'];
2653 if ($ih > $pb['bpa']['h']) {
2654 $iw = $iw * $pb['bpa']['h'] / $ih;
2655 $ih = $pb['bpa']['h'];
2656 }
2657 } elseif ($size['w'] == 'cover') {
2658 // Scale the image, while preserving its intrinsic aspect ratio (if any), to the smallest size such that both its width and its height can completely cover the background positioning area.
2659 $ih = $ih * $pb['bpa']['w'] / $iw;
2660 $iw = $pb['bpa']['w'];
2661 if ($ih < $pb['bpa']['h']) {
2662 $iw = $iw * $ih / $pb['bpa']['h'];
2663 $ih = $pb['bpa']['h'];
2664 }
2665 } else {
2666 if (NumericString::containsPercentChar($size['w'])) {
2667 $size['w'] = NumericString::removePercentChar($size['w']);
2668 $size['w'] /= 100;
2669 $size['w'] = ($pb['bpa']['w'] * $size['w']);
2670 }
2671 if (NumericString::containsPercentChar($size['h'])) {
2672 $size['h'] = NumericString::removePercentChar($size['h']);
2673 $size['h'] /= 100;
2674 $size['h'] = ($pb['bpa']['h'] * $size['h']);
2675 }
2676 if ($size['w'] == 'auto' && $size['h'] == 'auto') {
2677 $iw = $iw;
2678 $ih = $ih;
2679 } elseif ($size['w'] == 'auto' && $size['h'] != 'auto') {
2680 $iw = $iw * $size['h'] / $ih;
2681 $ih = $size['h'];
2682 } elseif ($size['w'] != 'auto' && $size['h'] == 'auto') {
2683 $ih = $ih * $size['w'] / $iw;
2684 $iw = $size['w'];
2685 } else {
2686 $iw = $size['w'];
2687 $ih = $size['h'];
2688 }
2689 }
2690 }
2691
2692 // Number to repeat
2693 if (isset($pb['x_repeat']) && $pb['x_repeat']) {
2694 $nx = ceil($pb['w'] / $iw) + 1;
2695 } else {
2696 $nx = 1;
2697 }
2698 if (isset($pb['y_repeat']) && $pb['y_repeat']) {
2699 $ny = ceil($pb['h'] / $ih) + 1;
2700 } else {
2701 $ny = 1;
2702 }
2703
2704 $x_pos = $pb['x_pos'];
2706 $x_pos = NumericString::removePercentChar($x_pos);
2707 $x_pos /= 100;
2708 $x_pos = ($pb['bpa']['w'] * $x_pos) - ($iw * $x_pos);
2709 }
2710 $y_pos = $pb['y_pos'];
2712 $y_pos = NumericString::removePercentChar($y_pos);
2713 $y_pos /= 100;
2714 $y_pos = ($pb['bpa']['h'] * $y_pos) - ($ih * $y_pos);
2715 }
2716 if ($nx > 1) {
2717 while ($x_pos > ($pb['x'] - $pb['bpa']['x'])) {
2718 $x_pos -= $iw;
2719 }
2720 }
2721 if ($ny > 1) {
2722 while ($y_pos > ($pb['y'] - $pb['bpa']['y'])) {
2723 $y_pos -= $ih;
2724 }
2725 }
2726 for ($xi = 0; $xi < $nx; $xi++) {
2727 for ($yi = 0; $yi < $ny; $yi++) {
2728 $x = $x0 + $x_pos + ($iw * $xi);
2729 $y = $y0 + $y_pos + ($ih * $yi);
2730 if ($pb['opacity'] > 0 && $pb['opacity'] < 1) {
2731 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2732 } else {
2733 $opac = '';
2734 }
2735 $s .= sprintf("q %s %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $opac, $iw * Mpdf::SCALE, $ih * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($y + $ih)) * Mpdf::SCALE, $pb['image_id']) . "\n";
2736 }
2737 }
2738 } else {
2739 if (($pb['opacity'] > 0 || $pb['opacity'] === '0') && $pb['opacity'] < 1) {
2740 $opac = $this->SetAlpha($pb['opacity'], 'Normal', true);
2741 } else {
2742 $opac = '';
2743 }
2744 $s .= sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $x, $y, $w, $h) . "\n";
2745 }
2746
2747 if (isset($pb['clippath']) && $pb['clippath']) {
2748 $s .= 'Q' . "\n";
2749 }
2750 }
2751 }
2752 }
2753 /* -- END BACKGROUNDS -- */
2754 return $s;
2755 }
2756
2757 function BeginLayer($id)
2758 {
2759 if ($this->current_layer > 0) {
2760 $this->EndLayer();
2761 }
2762 if ($id < 1) {
2763 return false;
2764 }
2765 if (!isset($this->layers[$id])) {
2766 $this->layers[$id] = ['name' => 'Layer ' . ($id)];
2767 if (($this->PDFA || $this->PDFX)) {
2768 $this->PDFAXwarnings[] = "Cannot use layers when using PDFA or PDFX";
2769 return '';
2770 } elseif (!$this->PDFA && !$this->PDFX) {
2771 $this->pdf_version = '1.5';
2772 }
2773 }
2774 $this->current_layer = $id;
2775 $this->writer->write('/OCZ-index /ZI' . $id . ' BDC');
2776
2777 $this->pageoutput[$this->page] = [];
2778 }
2779
2780 function EndLayer()
2781 {
2782 if ($this->current_layer > 0) {
2783 $this->writer->write('EMCZ-index');
2784 $this->current_layer = 0;
2785 }
2786 }
2787
2788 function AddPageByArray($a)
2789 {
2790 if (!is_array($a)) {
2791 $a = [];
2792 }
2793
2794 $orientation = (isset($a['orientation']) ? $a['orientation'] : '');
2795 $condition = (isset($a['condition']) ? $a['condition'] : (isset($a['type']) ? $a['type'] : ''));
2796 $resetpagenum = (isset($a['resetpagenum']) ? $a['resetpagenum'] : '');
2797 $pagenumstyle = (isset($a['pagenumstyle']) ? $a['pagenumstyle'] : '');
2798 $suppress = (isset($a['suppress']) ? $a['suppress'] : '');
2799 $mgl = (isset($a['mgl']) ? $a['mgl'] : (isset($a['margin-left']) ? $a['margin-left'] : ''));
2800 $mgr = (isset($a['mgr']) ? $a['mgr'] : (isset($a['margin-right']) ? $a['margin-right'] : ''));
2801 $mgt = (isset($a['mgt']) ? $a['mgt'] : (isset($a['margin-top']) ? $a['margin-top'] : ''));
2802 $mgb = (isset($a['mgb']) ? $a['mgb'] : (isset($a['margin-bottom']) ? $a['margin-bottom'] : ''));
2803 $mgh = (isset($a['mgh']) ? $a['mgh'] : (isset($a['margin-header']) ? $a['margin-header'] : ''));
2804 $mgf = (isset($a['mgf']) ? $a['mgf'] : (isset($a['margin-footer']) ? $a['margin-footer'] : ''));
2805 $ohname = (isset($a['ohname']) ? $a['ohname'] : (isset($a['odd-header-name']) ? $a['odd-header-name'] : ''));
2806 $ehname = (isset($a['ehname']) ? $a['ehname'] : (isset($a['even-header-name']) ? $a['even-header-name'] : ''));
2807 $ofname = (isset($a['ofname']) ? $a['ofname'] : (isset($a['odd-footer-name']) ? $a['odd-footer-name'] : ''));
2808 $efname = (isset($a['efname']) ? $a['efname'] : (isset($a['even-footer-name']) ? $a['even-footer-name'] : ''));
2809 $ohvalue = (isset($a['ohvalue']) ? $a['ohvalue'] : (isset($a['odd-header-value']) ? $a['odd-header-value'] : 0));
2810 $ehvalue = (isset($a['ehvalue']) ? $a['ehvalue'] : (isset($a['even-header-value']) ? $a['even-header-value'] : 0));
2811 $ofvalue = (isset($a['ofvalue']) ? $a['ofvalue'] : (isset($a['odd-footer-value']) ? $a['odd-footer-value'] : 0));
2812 $efvalue = (isset($a['efvalue']) ? $a['efvalue'] : (isset($a['even-footer-value']) ? $a['even-footer-value'] : 0));
2813 $pagesel = (isset($a['pagesel']) ? $a['pagesel'] : (isset($a['pageselector']) ? $a['pageselector'] : ''));
2814 $newformat = (isset($a['newformat']) ? $a['newformat'] : (isset($a['sheet-size']) ? $a['sheet-size'] : ''));
2815
2816 $this->AddPage($orientation, $condition, $resetpagenum, $pagenumstyle, $suppress, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $newformat);
2817 }
2818
2819 // mPDF 6 pagebreaktype
2820 function _preForcedPagebreak($pagebreaktype)
2821 {
2822 if ($pagebreaktype == 'cloneall') {
2823 // Close any open block tags
2824 $arr = [];
2825 $ai = 0;
2826 for ($b = $this->blklvl; $b > 0; $b--) {
2827 $this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
2828 }
2829 if ($this->blklvl == 0 && !empty($this->textbuffer)) { // Output previously buffered content
2830 $this->printbuffer($this->textbuffer, 1);
2831 $this->textbuffer = [];
2832 }
2833 } elseif ($pagebreaktype == 'clonebycss') {
2834 // Close open block tags whilst box-decoration-break==clone
2835 $arr = [];
2836 $ai = 0;
2837 for ($b = $this->blklvl; $b > 0; $b--) {
2838 if (isset($this->blk[$b]['box_decoration_break']) && $this->blk[$b]['box_decoration_break'] == 'clone') {
2839 $this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
2840 } else {
2841 if ($b == $this->blklvl && !empty($this->textbuffer)) { // Output previously buffered content
2842 $this->printbuffer($this->textbuffer, 1);
2843 $this->textbuffer = [];
2844 }
2845 break;
2846 }
2847 }
2848 } elseif (!empty($this->textbuffer)) { // Output previously buffered content
2849 $this->printbuffer($this->textbuffer, 1);
2850 $this->textbuffer = [];
2851 }
2852 }
2853
2854 // mPDF 6 pagebreaktype
2855 function _postForcedPagebreak($pagebreaktype, $startpage, $save_blk, $save_blklvl)
2856 {
2857 if ($pagebreaktype == 'cloneall') {
2858 $this->blk = [];
2859 $this->blk[0] = $save_blk[0];
2860 // Re-open block tags
2861 $this->blklvl = 0;
2862 $arr = [];
2863 $i = 0;
2864 for ($b = 1; $b <= $save_blklvl; $b++) {
2865 $this->tag->OpenTag($save_blk[$b]['tag'], $save_blk[$b]['attr'], $arr, $i);
2866 }
2867 } elseif ($pagebreaktype == 'clonebycss') {
2868 $this->blk = [];
2869 $this->blk[0] = $save_blk[0];
2870 // Don't re-open tags for lowest level elements - so need to do some adjustments
2871 for ($b = 1; $b <= $this->blklvl; $b++) {
2872 $this->blk[$b] = $save_blk[$b];
2873 $this->blk[$b]['startpage'] = 0;
2874 $this->blk[$b]['y0'] = $this->y; // ?? $this->tMargin
2875 if (($this->page - $startpage) % 2) {
2876 if (isset($this->blk[$b]['x0'])) {
2877 $this->blk[$b]['x0'] += $this->MarginCorrection;
2878 } else {
2879 $this->blk[$b]['x0'] = $this->MarginCorrection;
2880 }
2881 }
2882 // for Float DIV
2883 $this->blk[$b]['marginCorrected'][$this->page] = true;
2884 }
2885
2886 // Re-open block tags for any that have box_decoration_break==clone
2887 $arr = [];
2888 $i = 0;
2889 for ($b = $this->blklvl + 1; $b <= $save_blklvl; $b++) {
2890 if ($b < $this->blklvl) {
2891 $this->lastblocklevelchange = -1;
2892 }
2893 $this->tag->OpenTag($save_blk[$b]['tag'], $save_blk[$b]['attr'], $arr, $i);
2894 }
2895 if ($this->blk[$this->blklvl]['box_decoration_break'] != 'clone') {
2896 $this->lastblocklevelchange = -1;
2897 }
2898 } else {
2899 $this->lastblocklevelchange = -1;
2900 }
2901 }
2902
2903 function AddPage(
2904 $orientation = '',
2905 $condition = '',
2906 $resetpagenum = '',
2907 $pagenumstyle = '',
2908 $suppress = '',
2909 $mgl = '',
2910 $mgr = '',
2911 $mgt = '',
2912 $mgb = '',
2913 $mgh = '',
2914 $mgf = '',
2915 $ohname = '',
2916 $ehname = '',
2917 $ofname = '',
2918 $efname = '',
2919 $ohvalue = 0,
2920 $ehvalue = 0,
2921 $ofvalue = 0,
2922 $efvalue = 0,
2923 $pagesel = '',
2924 $newformat = ''
2925 ) {
2926 /* -- CSS-FLOAT -- */
2927 // Float DIV
2928 // Cannot do with columns on, or if any change in page orientation/margins etc.
2929 // If next page already exists - i.e background /headers and footers already written
2930 if ($this->state > 0 && $this->page < count($this->pages)) {
2931 $bak_cml = $this->cMarginL;
2932 $bak_cmr = $this->cMarginR;
2933 $bak_dw = $this->divwidth;
2934 // Paint Div Border if necessary
2935 if ($this->blklvl > 0) {
2936 $save_tr = $this->table_rotate; // *TABLES*
2937 $this->table_rotate = 0; // *TABLES*
2938 if (isset($this->blk[$this->blklvl]['y0']) && $this->y == $this->blk[$this->blklvl]['y0']) {
2939 $this->blk[$this->blklvl]['startpage'] ++;
2940 }
2941 if ((isset($this->blk[$this->blklvl]['y0']) && $this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table']) {
2942 $toplvl = $this->blklvl;
2943 } else {
2944 $toplvl = $this->blklvl - 1;
2945 }
2946 $sy = $this->y;
2947 for ($bl = 1; $bl <= $toplvl; $bl++) {
2948 $this->PaintDivBB('pagebottom', 0, $bl);
2949 }
2950 $this->y = $sy;
2951 $this->table_rotate = $save_tr; // *TABLES*
2952 }
2953 $s = $this->PrintPageBackgrounds();
2954
2955 // Writes after the marker so not overwritten later by page background etc.
2956 $this->pages[$this->page] = preg_replace(
2957 '/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/',
2958 '\\1' . "\n" . $s . "\n",
2959 $this->pages[$this->page]
2960 );
2961
2962 $this->pageBackgrounds = [];
2963 $family = $this->FontFamily;
2964 $style = $this->FontStyle;
2965 $size = $this->FontSizePt;
2966 $lw = $this->LineWidth;
2967 $dc = $this->DrawColor;
2968 $fc = $this->FillColor;
2969 $tc = $this->TextColor;
2970 $cf = $this->ColorFlag;
2971
2972 $this->printfloatbuffer();
2973
2974 // Move to next page
2975 $this->page++;
2976
2977 $this->ResetMargins();
2978 $this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);
2979 $this->x = $this->lMargin;
2980 $this->y = $this->tMargin;
2981 $this->FontFamily = '';
2982 $this->writer->write('2 J');
2983 $this->LineWidth = $lw;
2984 $this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE));
2985
2986 if ($family) {
2987 $this->SetFont($family, $style, $size, true, true);
2988 }
2989
2990 $this->DrawColor = $dc;
2991
2992 if ($dc != $this->defDrawColor) {
2993 $this->writer->write($dc);
2994 }
2995
2996 $this->FillColor = $fc;
2997
2998 if ($fc != $this->defFillColor) {
2999 $this->writer->write($fc);
3000 }
3001
3002 $this->TextColor = $tc;
3003 $this->ColorFlag = $cf;
3004
3005 for ($bl = 1; $bl <= $this->blklvl; $bl++) {
3006 $this->blk[$bl]['y0'] = $this->y;
3007 // Don't correct more than once for background DIV containing a Float
3008 if (!isset($this->blk[$bl]['marginCorrected'][$this->page])) {
3009 if (isset($this->blk[$bl]['x0'])) {
3010 $this->blk[$bl]['x0'] += $this->MarginCorrection;
3011 } else {
3012 $this->blk[$bl]['x0'] = $this->MarginCorrection;
3013 }
3014 }
3015 $this->blk[$bl]['marginCorrected'][$this->page] = true;
3016 }
3017
3018 $this->cMarginL = $bak_cml;
3019 $this->cMarginR = $bak_cmr;
3020 $this->divwidth = $bak_dw;
3021
3022 return '';
3023 }
3024 /* -- END CSS-FLOAT -- */
3025
3026 // Start a new page
3027 if ($this->state == 0) {
3028 $this->Open();
3029 }
3030
3031 $bak_cml = $this->cMarginL;
3032 $bak_cmr = $this->cMarginR;
3033 $bak_dw = $this->divwidth;
3034
3035 $bak_lh = $this->lineheight;
3036
3037 $orientation = substr(strtoupper($orientation), 0, 1);
3038 $condition = strtoupper($condition);
3039
3040
3041 if ($condition == 'E') { // only adds new page if needed to create an Even page
3042 if (!$this->mirrorMargins || ($this->page) % 2 == 0) {
3043 return false;
3044 }
3045 } elseif ($condition == 'O') { // only adds new page if needed to create an Odd page
3046 if (!$this->mirrorMargins || ($this->page) % 2 == 1) {
3047 return false;
3048 }
3049 } elseif ($condition == 'NEXT-EVEN') { // always adds at least one new page to create an Even page
3050 if (!$this->mirrorMargins) {
3051 $condition = '';
3052 } else {
3053 if ($pagesel) {
3054 $pbch = $pagesel;
3055 $pagesel = '';
3056 } // *CSS-PAGE*
3057 else {
3058 $pbch = false;
3059 } // *CSS-PAGE*
3060 $this->AddPage($this->CurOrientation, 'O');
3061 $this->extrapagebreak = true; // mPDF 6 pagebreaktype
3062 if ($pbch) {
3063 $pagesel = $pbch;
3064 } // *CSS-PAGE*
3065 $condition = '';
3066 }
3067 } elseif ($condition == 'NEXT-ODD') { // always adds at least one new page to create an Odd page
3068 if (!$this->mirrorMargins) {
3069 $condition = '';
3070 } else {
3071 if ($pagesel) {
3072 $pbch = $pagesel;
3073 $pagesel = '';
3074 } // *CSS-PAGE*
3075 else {
3076 $pbch = false;
3077 } // *CSS-PAGE*
3078 $this->AddPage($this->CurOrientation, 'E');
3079 $this->extrapagebreak = true; // mPDF 6 pagebreaktype
3080 if ($pbch) {
3081 $pagesel = $pbch;
3082 } // *CSS-PAGE*
3083 $condition = '';
3084 }
3085 }
3086
3087 if ($resetpagenum || $pagenumstyle || $suppress) {
3088 $this->PageNumSubstitutions[] = ['from' => ($this->page + 1), 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress];
3089 }
3090
3091 $save_tr = $this->table_rotate; // *TABLES*
3092 $this->table_rotate = 0; // *TABLES*
3093 $save_kwt = $this->kwt;
3094 $this->kwt = 0;
3095 $save_layer = $this->current_layer;
3096 $save_vis = $this->visibility;
3097
3098 if ($this->visibility != 'visible') {
3099 $this->SetVisibility('visible');
3100 }
3101
3102 $this->EndLayer();
3103
3104 // Paint Div Border if necessary
3105 // PAINTS BACKGROUND COLOUR OR BORDERS for DIV - DISABLED FOR COLUMNS (cf. AcceptPageBreak) AT PRESENT in ->PaintDivBB
3106 if (!$this->ColActive && $this->blklvl > 0) {
3107 if (isset($this->blk[$this->blklvl]['y0']) && $this->y == $this->blk[$this->blklvl]['y0'] && !$this->extrapagebreak) { // mPDF 6 pagebreaktype
3108 if (isset($this->blk[$this->blklvl]['startpage'])) {
3109 $this->blk[$this->blklvl]['startpage'] ++;
3110 } else {
3111 $this->blk[$this->blklvl]['startpage'] = 1;
3112 }
3113 }
3114 if ((isset($this->blk[$this->blklvl]['y0']) && $this->y > $this->blk[$this->blklvl]['y0']) || $this->flowingBlockAttr['is_table'] || $this->extrapagebreak) {
3115 $toplvl = $this->blklvl;
3116 } // mPDF 6 pagebreaktype
3117 else {
3118 $toplvl = $this->blklvl - 1;
3119 }
3120 $sy = $this->y;
3121 for ($bl = 1; $bl <= $toplvl; $bl++) {
3122 if (isset($this->blk[$bl]['z-index']) && $this->blk[$bl]['z-index'] > 0) {
3123 $this->BeginLayer($this->blk[$bl]['z-index']);
3124 }
3125 if (isset($this->blk[$bl]['visibility']) && $this->blk[$bl]['visibility'] && $this->blk[$bl]['visibility'] != 'visible') {
3126 $this->SetVisibility($this->blk[$bl]['visibility']);
3127 }
3128 $this->PaintDivBB('pagebottom', 0, $bl);
3129 }
3130 $this->y = $sy;
3131 // RESET block y0 and x0 - see below
3132 }
3133 $this->extrapagebreak = false; // mPDF 6 pagebreaktype
3134
3135 if ($this->visibility != 'visible') {
3136 $this->SetVisibility('visible');
3137 }
3138
3139 $this->EndLayer();
3140
3141 // BODY Backgrounds
3142 if ($this->page > 0) {
3143 $s = '';
3144 $s .= $this->PrintBodyBackgrounds();
3145
3146 $s .= $this->PrintPageBackgrounds();
3147 $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', "\n" . $s . "\n" . '\\1', $this->pages[$this->page]);
3148 $this->pageBackgrounds = [];
3149 }
3150
3151 $save_kt = $this->keep_block_together;
3152 $this->keep_block_together = 0;
3153
3154 $save_cols = false;
3155
3156 /* -- COLUMNS -- */
3157 if ($this->ColActive) {
3158 $save_cols = true;
3159 $save_nbcol = $this->NbCol; // other values of gap and vAlign will not change by setting Columns off
3160 $this->SetColumns(0);
3161 }
3162 /* -- END COLUMNS -- */
3163
3164 $family = $this->FontFamily;
3165 $style = $this->FontStyle;
3166 $size = $this->FontSizePt;
3167 $this->ColumnAdjust = true; // enables column height adjustment for the page
3168 $lw = $this->LineWidth;
3169 $dc = $this->DrawColor;
3170 $fc = $this->FillColor;
3171 $tc = $this->TextColor;
3172 $cf = $this->ColorFlag;
3173 if ($this->page > 0) {
3174 // Page footer
3175 $this->InFooter = true;
3176
3177 $this->Reset();
3178 $this->pageoutput[$this->page] = [];
3179
3180 $this->Footer();
3181 // Close page
3182 $this->_endpage();
3183 }
3184
3185 // Start new page
3186 $pageBeforeNewPage = $this->page;
3187 $this->_beginpage($orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $newformat);
3188 $isNewPage = $pageBeforeNewPage !== $this->page;
3189
3190 if ($this->docTemplate) {
3192
3193 $pagecount = $this->setSourceFile($this->docTemplate);
3194 if (($this->page - $this->docTemplateStart) > $pagecount) {
3195 if ($this->docTemplateContinue) {
3196 if ($this->docTemplateContinue2pages && $pagecount >= 2 && (0 === $this->page % 2)) {
3197 $tplIdx = $this->importPage(($pagecount - 1));
3198 $this->useTemplate($tplIdx);
3199 } else {
3200 $tplIdx = $this->importPage($pagecount);
3201 $this->useTemplate($tplIdx);
3202 }
3203 }
3204 } else {
3205 $tplIdx = $this->importPage(($this->page - $this->docTemplateStart));
3206 $this->useTemplate($tplIdx);
3207 }
3208
3209 $this->currentReaderId = $currentReaderId;
3210 }
3211
3212 if ($this->pageTemplate) {
3213 $this->useTemplate($this->pageTemplate);
3214 }
3215
3216 // Only add the headers if it's a new page
3217 if ($isNewPage) {
3218 // Tiling Patterns
3219 $this->writer->write('___PAGE___START' . $this->uniqstr);
3220 $this->writer->write('___BACKGROUND___PATTERNS' . $this->uniqstr);
3221 $this->writer->write('___HEADER___MARKER' . $this->uniqstr);
3222 }
3223
3224 $this->pageBackgrounds = [];
3225
3226 // Set line cap style to square
3227 $this->SetLineCap(2);
3228 // Set line width
3229 $this->LineWidth = $lw;
3230 $this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE));
3231 // Set font
3232 if ($family) {
3233 $this->SetFont($family, $style, $size, true, true); // forces write
3234 }
3235
3236 // Set colors
3237 $this->DrawColor = $dc;
3238 if ($dc != $this->defDrawColor) {
3239 $this->writer->write($dc);
3240 }
3241 $this->FillColor = $fc;
3242 if ($fc != $this->defFillColor) {
3243 $this->writer->write($fc);
3244 }
3245 $this->TextColor = $tc;
3246 $this->ColorFlag = $cf;
3247
3248 // Page header
3249 $this->Header();
3250
3251 // Restore line width
3252 if ($this->LineWidth != $lw) {
3253 $this->LineWidth = $lw;
3254 $this->writer->write(sprintf('%.3F w', $lw * Mpdf::SCALE));
3255 }
3256 // Restore font
3257 if ($family) {
3258 $this->SetFont($family, $style, $size, true, true); // forces write
3259 }
3260
3261 // Restore colors
3262 if ($this->DrawColor != $dc) {
3263 $this->DrawColor = $dc;
3264 $this->writer->write($dc);
3265 }
3266 if ($this->FillColor != $fc) {
3267 $this->FillColor = $fc;
3268 $this->writer->write($fc);
3269 }
3270 $this->TextColor = $tc;
3271 $this->ColorFlag = $cf;
3272 $this->InFooter = false;
3273
3274 if ($save_layer > 0) {
3275 $this->BeginLayer($save_layer);
3276 }
3277
3278 if ($save_vis != 'visible') {
3279 $this->SetVisibility($save_vis);
3280 }
3281
3282 /* -- COLUMNS -- */
3283 if ($save_cols) {
3284 // Restore columns
3285 $this->SetColumns($save_nbcol, $this->colvAlign, $this->ColGap);
3286 }
3287 if ($this->ColActive) {
3288 $this->SetCol(0);
3289 }
3290 /* -- END COLUMNS -- */
3291
3292
3293 // RESET BLOCK BORDER TOP
3294 if (!$this->ColActive) {
3295 for ($bl = 1; $bl <= $this->blklvl; $bl++) {
3296 $this->blk[$bl]['y0'] = $this->y;
3297 if (isset($this->blk[$bl]['x0'])) {
3298 $this->blk[$bl]['x0'] += $this->MarginCorrection;
3299 } else {
3300 $this->blk[$bl]['x0'] = $this->MarginCorrection;
3301 }
3302 // Added mPDF 3.0 Float DIV
3303 $this->blk[$bl]['marginCorrected'][$this->page] = true;
3304 }
3305 }
3306
3307
3308 $this->table_rotate = $save_tr; // *TABLES*
3309 $this->kwt = $save_kwt;
3310
3311 $this->keep_block_together = $save_kt;
3312
3313 $this->cMarginL = $bak_cml;
3314 $this->cMarginR = $bak_cmr;
3315 $this->divwidth = $bak_dw;
3316
3317 $this->lineheight = $bak_lh;
3318 }
3319
3325 function PageNo()
3326 {
3327 return $this->page;
3328 }
3329
3331 {
3332 $colors = @file($file);
3333 if (!$colors) {
3334 throw new \Mpdf\MpdfException("Cannot load spot colors file - " . $file);
3335 }
3336 foreach ($colors as $sc) {
3337 list($name, $c, $m, $y, $k) = preg_split("/\t/", $sc);
3338 $c = intval($c);
3339 $m = intval($m);
3340 $y = intval($y);
3341 $k = intval($k);
3342 $this->AddSpotColor($name, $c, $m, $y, $k);
3343 }
3344 }
3345
3346 function AddSpotColor($name, $c, $m, $y, $k)
3347 {
3348 $name = strtoupper(trim($name));
3349 if (!isset($this->spotColors[$name])) {
3350 $i = count($this->spotColors) + 1;
3351 $this->spotColors[$name] = ['i' => $i, 'c' => $c, 'm' => $m, 'y' => $y, 'k' => $k];
3352 $this->spotColorIDs[$i] = $name;
3353 }
3354 }
3355
3356 function SetColor($col, $type = '')
3357 {
3358 $out = '';
3359 if (!$col) {
3360 return '';
3361 } // mPDF 6
3362 if ($col[0] == 3 || $col[0] == 5) { // RGB / RGBa
3363 $out = sprintf('%.3F %.3F %.3F rg', ord($col[1]) / 255, ord($col[2]) / 255, ord($col[3]) / 255);
3364 } elseif ($col[0] == 1) { // GRAYSCALE
3365 $out = sprintf('%.3F g', ord($col[1]) / 255);
3366 } elseif ($col[0] == 2) { // SPOT COLOR
3367 $out = sprintf('/CS%d cs %.3F scn', ord($col[1]), ord($col[2]) / 100);
3368 } elseif ($col[0] == 4 || $col[0] == 6) { // CMYK / CMYKa
3369 $out = sprintf('%.3F %.3F %.3F %.3F k', ord($col[1]) / 100, ord($col[2]) / 100, ord($col[3]) / 100, ord($col[4]) / 100);
3370 }
3371 if ($type == 'Draw') {
3372 $out = strtoupper($out);
3373 } // e.g. rg => RG
3374 elseif ($type == 'CodeOnly') {
3375 $out = preg_replace('/\s(rg|g|k)/', '', $out);
3376 }
3377 return $out;
3378 }
3379
3380 function SetDColor($col, $return = false)
3381 {
3382 $out = $this->SetColor($col, 'Draw');
3383 if ($return) {
3384 return $out;
3385 }
3386 if ($out == '') {
3387 return '';
3388 }
3389 $this->DrawColor = $out;
3390 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['DrawColor']) && $this->pageoutput[$this->page]['DrawColor'] != $this->DrawColor) || !isset($this->pageoutput[$this->page]['DrawColor']))) {
3391 $this->writer->write($this->DrawColor);
3392 }
3393 $this->pageoutput[$this->page]['DrawColor'] = $this->DrawColor;
3394 }
3395
3396 function SetFColor($col, $return = false)
3397 {
3398 $out = $this->SetColor($col, 'Fill');
3399 if ($return) {
3400 return $out;
3401 }
3402 if ($out == '') {
3403 return '';
3404 }
3405 $this->FillColor = $out;
3406 $this->ColorFlag = ($out != $this->TextColor);
3407 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['FillColor']) && $this->pageoutput[$this->page]['FillColor'] != $this->FillColor) || !isset($this->pageoutput[$this->page]['FillColor']))) {
3408 $this->writer->write($this->FillColor);
3409 }
3410 $this->pageoutput[$this->page]['FillColor'] = $this->FillColor;
3411 }
3412
3413 function SetTColor($col, $return = false)
3414 {
3415 $out = $this->SetColor($col, 'Text');
3416 if ($return) {
3417 return $out;
3418 }
3419 if ($out == '') {
3420 return '';
3421 }
3422 $this->TextColor = $out;
3423 $this->ColorFlag = ($this->FillColor != $out);
3424 }
3425
3426 function SetDrawColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
3427 {
3428 // Set color for all stroking operations
3429 $col = [];
3430 if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
3431 $col = $this->colorConverter->convert($r, $this->PDFAXwarnings);
3432 } elseif ($col4 == -1) {
3433 $col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings);
3434 } else {
3435 $col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings);
3436 }
3437 $out = $this->SetDColor($col, $return);
3438 return $out;
3439 }
3440
3441 function SetFillColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
3442 {
3443 // Set color for all filling operations
3444 $col = [];
3445 if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
3446 $col = $this->colorConverter->convert($r, $this->PDFAXwarnings);
3447 } elseif ($col4 == -1) {
3448 $col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings);
3449 } else {
3450 $col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings);
3451 }
3452 $out = $this->SetFColor($col, $return);
3453 return $out;
3454 }
3455
3456 function SetTextColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
3457 {
3458 // Set color for text
3459 $col = [];
3460 if (($r == 0 and $g == 0 and $b == 0 && $col4 == -1) or $g == -1) {
3461 $col = $this->colorConverter->convert($r, $this->PDFAXwarnings);
3462 } elseif ($col4 == -1) {
3463 $col = $this->colorConverter->convert('rgb(' . $r . ',' . $g . ',' . $b . ')', $this->PDFAXwarnings);
3464 } else {
3465 $col = $this->colorConverter->convert('cmyk(' . $r . ',' . $g . ',' . $b . ',' . $col4 . ')', $this->PDFAXwarnings);
3466 }
3467 $out = $this->SetTColor($col, $return);
3468 return $out;
3469 }
3470
3471 function _getCharWidth(&$cw, $u, $isdef = true)
3472 {
3473 $w = 0;
3474
3475 if ($u == 0) {
3476 $w = false;
3477 } elseif (isset($cw[$u * 2 + 1])) {
3478 $w = (ord($cw[$u * 2]) << 8) + ord($cw[$u * 2 + 1]);
3479 }
3480
3481 if ($w == 65535) {
3482 return 0;
3483 } elseif ($w) {
3484 return $w;
3485 } elseif ($isdef) {
3486 return false;
3487 } else {
3488 return 0;
3489 }
3490 }
3491
3492 function _charDefined(&$cw, $u)
3493 {
3494 $w = 0;
3495 if ($u == 0) {
3496 return false;
3497 }
3498 if (isset($cw[$u * 2 + 1])) {
3499 $w = (ord($cw[$u * 2]) << 8) + ord($cw[$u * 2 + 1]);
3500 }
3501
3502 return (bool) $w;
3503 }
3504
3505 function GetCharWidthCore($c)
3506 {
3507 // Get width of a single character in the current Core font
3508 $c = (string) $c;
3509 $w = 0;
3510 // Soft Hyphens chr(173)
3511 if ($c == chr(173) && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
3512 return 0;
3513 } elseif (($this->textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[ord($c)])) { // mPDF 5.7.1
3514 $charw = $this->CurrentFont['cw'][chr($this->upperCase[ord($c)])];
3515 if ($charw !== false) {
3516 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3517 $w+=$charw;
3518 }
3519 } elseif (isset($this->CurrentFont['cw'][$c])) {
3520 $w += $this->CurrentFont['cw'][$c];
3521 } elseif (isset($this->CurrentFont['cw'][ord($c)])) {
3522 $w += $this->CurrentFont['cw'][ord($c)];
3523 }
3524 $w *= ($this->FontSize / 1000);
3525 if ($this->minwSpacing || $this->fixedlSpacing) {
3526 if ($c == ' ') {
3527 $nb_spaces = 1;
3528 } else {
3529 $nb_spaces = 0;
3530 }
3531 $w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing);
3532 }
3533 return ($w);
3534 }
3535
3536 function GetCharWidthNonCore($c, $addSubset = true)
3537 {
3538 // Get width of a single character in the current Non-Core font
3539 $c = (string) $c;
3540 $w = 0;
3541 $unicode = $this->UTF8StringToArray($c, $addSubset);
3542 $char = $unicode[0];
3543 /* -- CJK-FONTS -- */
3544 if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts
3545 if ($char == 173) {
3546 return 0;
3547 } // Soft Hyphens
3548 elseif (isset($this->CurrentFont['cw'][$char])) {
3549 $w+=$this->CurrentFont['cw'][$char];
3550 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3551 $w += $this->CurrentFont['MissingWidth'];
3552 } else {
3553 $w += 500;
3554 }
3555 } else {
3556 /* -- END CJK-FONTS -- */
3557 if ($char == 173) {
3558 return 0;
3559 } // Soft Hyphens
3560 elseif (($this->textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[$char])) { // mPDF 5.7.1
3561 $charw = $this->_getCharWidth($this->CurrentFont['cw'], $this->upperCase[$char]);
3562 if ($charw !== false) {
3563 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3564 $w+=$charw;
3565 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3566 $w += $this->CurrentFont['desc']['MissingWidth'];
3567 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3568 $w += $this->CurrentFont['MissingWidth'];
3569 } else {
3570 $w += 500;
3571 }
3572 } else {
3573 $charw = $this->_getCharWidth($this->CurrentFont['cw'], $char);
3574 if ($charw !== false) {
3575 $w+=$charw;
3576 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3577 $w += $this->CurrentFont['desc']['MissingWidth'];
3578 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3579 $w += $this->CurrentFont['MissingWidth'];
3580 } else {
3581 $w += 500;
3582 }
3583 }
3584 } // *CJK-FONTS*
3585 $w *= ($this->FontSize / 1000);
3586 if ($this->minwSpacing || $this->fixedlSpacing) {
3587 if ($c == ' ') {
3588 $nb_spaces = 1;
3589 } else {
3590 $nb_spaces = 0;
3591 }
3592 $w += $this->fixedlSpacing + ($nb_spaces * $this->minwSpacing);
3593 }
3594 return ($w);
3595 }
3596
3597 function GetCharWidth($c, $addSubset = true)
3598 {
3599 if (!$this->usingCoreFont) {
3600 return $this->GetCharWidthNonCore($c, $addSubset);
3601 } else {
3602 return $this->GetCharWidthCore($c);
3603 }
3604 }
3605
3606 function GetStringWidth($s, $addSubset = true, $OTLdata = false, $textvar = 0, $includeKashida = false)
3607 {
3608 // mPDF 5.7.1
3609 // Get width of a string in the current font
3610 $s = (string) $s;
3611 $cw = &$this->CurrentFont['cw'];
3612 $w = 0;
3613 $kerning = 0;
3614 $lastchar = 0;
3615 $nb_carac = 0;
3616 $nb_spaces = 0;
3617 $kashida = 0;
3618 // mPDF ITERATION
3619 if ($this->iterationCounter) {
3620 $s = preg_replace('/{iteration ([a-zA-Z0-9_]+)}/', '\\1', $s);
3621 }
3622 if (!$this->usingCoreFont) {
3623 $discards = substr_count($s, "\xc2\xad"); // mPDF 6 soft hyphens [U+00AD]
3624 $unicode = $this->UTF8StringToArray($s, $addSubset);
3625 if ($this->minwSpacing || $this->fixedlSpacing) {
3626 $nb_spaces = mb_substr_count($s, ' ', $this->mb_enc);
3627 $nb_carac = count($unicode) - $discards; // mPDF 6
3628 // mPDF 5.7.1
3629 // Use GPOS OTL
3630 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
3631 if (isset($OTLdata['group']) && $OTLdata['group']) {
3632 $nb_carac -= substr_count($OTLdata['group'], 'M');
3633 }
3634 }
3635 }
3636 /* -- CJK-FONTS -- */
3637 if ($this->CurrentFont['type'] == 'Type0') { // CJK Adobe fonts
3638 foreach ($unicode as $char) {
3639 if ($char == 0x00AD) {
3640 continue;
3641 } // mPDF 6 soft hyphens [U+00AD]
3642 if (isset($cw[$char])) {
3643 $w+=$cw[$char];
3644 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3645 $w += $this->CurrentFont['MissingWidth'];
3646 } else {
3647 $w += 500;
3648 }
3649 }
3650 } else {
3651 /* -- END CJK-FONTS -- */
3652 foreach ($unicode as $i => $char) {
3653 if ($char == 0x00AD) {
3654 continue;
3655 } // mPDF 6 soft hyphens [U+00AD]
3656 if (($textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[$char])) {
3657 $charw = $this->_getCharWidth($cw, $this->upperCase[$char]);
3658 if ($charw !== false) {
3659 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3660 $w+=$charw;
3661 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3662 $w += $this->CurrentFont['desc']['MissingWidth'];
3663 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3664 $w += $this->CurrentFont['MissingWidth'];
3665 } else {
3666 $w += 500;
3667 }
3668 } else {
3669 $charw = $this->_getCharWidth($cw, $char);
3670 if ($charw !== false) {
3671 $w+=$charw;
3672 } elseif (isset($this->CurrentFont['desc']['MissingWidth'])) {
3673 $w += $this->CurrentFont['desc']['MissingWidth'];
3674 } elseif (isset($this->CurrentFont['MissingWidth'])) {
3675 $w += $this->CurrentFont['MissingWidth'];
3676 } else {
3677 $w += 500;
3678 }
3679 // mPDF 5.7.1
3680 // Use GPOS OTL
3681 // ...GetStringWidth...
3682 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata)) {
3683 if (isset($OTLdata['GPOSinfo'][$i]['wDir']) && $OTLdata['GPOSinfo'][$i]['wDir'] == 'RTL') {
3684 if (isset($OTLdata['GPOSinfo'][$i]['XAdvanceR']) && $OTLdata['GPOSinfo'][$i]['XAdvanceR']) {
3685 $w += $OTLdata['GPOSinfo'][$i]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
3686 }
3687 } else {
3688 if (isset($OTLdata['GPOSinfo'][$i]['XAdvanceL']) && $OTLdata['GPOSinfo'][$i]['XAdvanceL']) {
3689 $w += $OTLdata['GPOSinfo'][$i]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
3690 }
3691 }
3692 // Kashida from GPOS
3693 // Kashida is set as an absolute length value (already set as a proportion based on useKashida %)
3694 if ($includeKashida && isset($OTLdata['GPOSinfo'][$i]['kashida_space']) && $OTLdata['GPOSinfo'][$i]['kashida_space']) {
3695 $kashida += $OTLdata['GPOSinfo'][$i]['kashida_space'];
3696 }
3697 }
3698 if (($textvar & TextVars::FC_KERNING) && $lastchar) {
3699 if (isset($this->CurrentFont['kerninfo'][$lastchar][$char])) {
3700 $kerning += $this->CurrentFont['kerninfo'][$lastchar][$char];
3701 }
3702 }
3703 $lastchar = $char;
3704 }
3705 }
3706 } // *CJK-FONTS*
3707 } else {
3708 if ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
3709 $s = str_replace(chr(173), '', $s);
3710 }
3711 $nb_carac = $l = strlen($s);
3712 if ($this->minwSpacing || $this->fixedlSpacing) {
3713 $nb_spaces = substr_count($s, ' ');
3714 }
3715 for ($i = 0; $i < $l; $i++) {
3716 if (($textvar & TextVars::FC_SMALLCAPS) && isset($this->upperCase[ord($s[$i])])) { // mPDF 5.7.1
3717 $charw = $cw[chr($this->upperCase[ord($s[$i])])];
3718 if ($charw !== false) {
3719 $charw = $charw * $this->smCapsScale * $this->smCapsStretch / 100;
3720 $w+=$charw;
3721 }
3722 } elseif (isset($cw[$s[$i]])) {
3723 $w += $cw[$s[$i]];
3724 } elseif (isset($cw[ord($s[$i])])) {
3725 $w += $cw[ord($s[$i])];
3726 }
3727 if (($textvar & TextVars::FC_KERNING) && $i > 0) { // mPDF 5.7.1
3728 if (isset($this->CurrentFont['kerninfo'][$s[($i - 1)]][$s[$i]])) {
3729 $kerning += $this->CurrentFont['kerninfo'][$s[($i - 1)]][$s[$i]];
3730 }
3731 }
3732 }
3733 }
3734 unset($cw);
3735 if ($textvar & TextVars::FC_KERNING) {
3736 $w += $kerning;
3737 } // mPDF 5.7.1
3738 $w *= ($this->FontSize / 1000);
3739 $w += (($nb_carac + $nb_spaces) * $this->fixedlSpacing) + ($nb_spaces * $this->minwSpacing);
3740 $w += $kashida / Mpdf::SCALE;
3741
3742 return ($w);
3743 }
3744
3745 function SetLineWidth($width)
3746 {
3747 // Set line width
3748 $this->LineWidth = $width;
3749 $lwout = (sprintf('%.3F w', $width * Mpdf::SCALE));
3750 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineWidth']) && $this->pageoutput[$this->page]['LineWidth'] != $lwout) || !isset($this->pageoutput[$this->page]['LineWidth']))) {
3751 $this->writer->write($lwout);
3752 }
3753 $this->pageoutput[$this->page]['LineWidth'] = $lwout;
3754 }
3755
3756 function Line($x1, $y1, $x2, $y2)
3757 {
3758 // Draw a line
3759 $this->writer->write(sprintf('%.3F %.3F m %.3F %.3F l S', $x1 * Mpdf::SCALE, ($this->h - $y1) * Mpdf::SCALE, $x2 * Mpdf::SCALE, ($this->h - $y2) * Mpdf::SCALE));
3760 }
3761
3762 function Arrow($x1, $y1, $x2, $y2, $headsize = 3, $fill = 'B', $angle = 25)
3763 {
3764 // F == fill // S == stroke // B == stroke and fill
3765 // angle = splay of arrowhead - 1 - 89 degrees
3766 if ($fill == 'F') {
3767 $fill = 'f';
3768 } elseif ($fill == 'FD' or $fill == 'DF' or $fill == 'B') {
3769 $fill = 'B';
3770 } else {
3771 $fill = 'S';
3772 }
3773 $a = atan2(($y2 - $y1), ($x2 - $x1));
3774 $b = $a + deg2rad($angle);
3775 $c = $a - deg2rad($angle);
3776 $x3 = $x2 - ($headsize * cos($b));
3777 $y3 = $this->h - ($y2 - ($headsize * sin($b)));
3778 $x4 = $x2 - ($headsize * cos($c));
3779 $y4 = $this->h - ($y2 - ($headsize * sin($c)));
3780
3781 $x5 = $x3 - ($x3 - $x4) / 2; // mid point of base of arrowhead - to join arrow line to
3782 $y5 = $y3 - ($y3 - $y4) / 2;
3783
3784 $s = '';
3785 $s .= sprintf('%.3F %.3F m %.3F %.3F l S', $x1 * Mpdf::SCALE, ($this->h - $y1) * Mpdf::SCALE, $x5 * Mpdf::SCALE, $y5 * Mpdf::SCALE);
3786 $this->writer->write($s);
3787
3788 $s = '';
3789 $s .= sprintf('%.3F %.3F m %.3F %.3F l %.3F %.3F l %.3F %.3F l %.3F %.3F l ', $x5 * Mpdf::SCALE, $y5 * Mpdf::SCALE, $x3 * Mpdf::SCALE, $y3 * Mpdf::SCALE, $x2 * Mpdf::SCALE, ($this->h - $y2) * Mpdf::SCALE, $x4 * Mpdf::SCALE, $y4 * Mpdf::SCALE, $x5 * Mpdf::SCALE, $y5 * Mpdf::SCALE);
3790 $s .= $fill;
3791 $this->writer->write($s);
3792 }
3793
3794 function Rect($x, $y, $w, $h, $style = '')
3795 {
3796 // Draw a rectangle
3797 if ($style == 'F') {
3798 $op = 'f';
3799 } elseif ($style == 'FD' or $style == 'DF') {
3800 $op = 'B';
3801 } else {
3802 $op = 'S';
3803 }
3804 $this->writer->write(sprintf('%.3F %.3F %.3F %.3F re %s', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $w * Mpdf::SCALE, -$h * Mpdf::SCALE, $op));
3805 }
3806
3807 function AddFontDirectory($directory)
3808 {
3809 $this->fontDir[] = $directory;
3810 $this->fontFileFinder->setDirectories($this->fontDir);
3811 }
3812
3813 function AddFont($family, $style = '')
3814 {
3815 if (empty($family)) {
3816 return;
3817 }
3818
3819 $family = strtolower($family);
3820 $style = strtoupper($style);
3821 $style = str_replace('U', '', $style);
3822
3823 if ($style == 'IB') {
3824 $style = 'BI';
3825 }
3826
3827 $fontkey = $family . $style;
3828
3829 // check if the font has been already added
3830 if (isset($this->fonts[$fontkey])) {
3831 return;
3832 }
3833
3834 /* -- CJK-FONTS -- */
3835 if (in_array($family, $this->available_CJK_fonts)) {
3836 if (empty($this->Big5_widths)) {
3837 require __DIR__ . '/../data/CJKdata.php';
3838 }
3839 $this->AddCJKFont($family); // don't need to add style
3840 return;
3841 }
3842 /* -- END CJK-FONTS -- */
3843
3844 if ($this->usingCoreFont) {
3845 throw new \Mpdf\MpdfException("mPDF Error - problem with Font management");
3846 }
3847
3848 $stylekey = $style;
3849 if (!$style) {
3850 $stylekey = 'R';
3851 }
3852
3853 if (!isset($this->fontdata[$family][$stylekey]) || !$this->fontdata[$family][$stylekey]) {
3854 throw new \Mpdf\MpdfException(sprintf('Font "%s%s%s" is not supported', $family, $style ? ' - ' : '', $style));
3855 }
3856
3857 /* Setup defaults */
3858 $font = [
3859 'name' => '',
3860 'type' => '',
3861 'desc' => '',
3862 'panose' => '',
3863 'unitsPerEm' => '',
3864 'up' => '',
3865 'ut' => '',
3866 'strs' => '',
3867 'strp' => '',
3868 'sip' => false,
3869 'smp' => false,
3870 'useOTL' => 0,
3871 'fontmetrics' => '',
3872 'haskerninfo' => false,
3873 'haskernGPOS' => false,
3874 'hassmallcapsGSUB' => false,
3875 'BMPselected' => false,
3876 'GSUBScriptLang' => [],
3877 'GSUBFeatures' => [],
3878 'GSUBLookups' => [],
3879 'GPOSScriptLang' => [],
3880 'GPOSFeatures' => [],
3881 'GPOSLookups' => [],
3882 'rtlPUAstr' => '',
3883 ];
3884
3885 $fontCacheFilename = $fontkey . '.mtx.json';
3886 if ($this->fontCache->jsonHas($fontCacheFilename)) {
3887 $font = $this->fontCache->jsonLoad($fontCacheFilename);
3888 }
3889
3890 $ttffile = $this->fontFileFinder->findFontFile($this->fontdata[$family][$stylekey]);
3891 $ttfstat = stat($ttffile);
3892
3893 $TTCfontID = isset($this->fontdata[$family]['TTCfontID'][$stylekey]) ? isset($this->fontdata[$family]['TTCfontID'][$stylekey]) : 0;
3894 $fontUseOTL = isset($this->fontdata[$family]['useOTL']) ? $this->fontdata[$family]['useOTL'] : false;
3895 $BMPonly = in_array($family, $this->BMPonly) ? true : false;
3896
3897 $regenerate = false;
3898 if ($BMPonly && !$font['BMPselected']) {
3899 $regenerate = true;
3900 } elseif (!$BMPonly && $font['BMPselected']) {
3901 $regenerate = true;
3902 }
3903
3904 if ($fontUseOTL && $font['useOTL'] != $fontUseOTL) {
3905 $regenerate = true;
3906 $font['useOTL'] = $fontUseOTL;
3907 } elseif (!$fontUseOTL && $font['useOTL']) {
3908 $regenerate = true;
3909 $font['useOTL'] = 0;
3910 }
3911
3912 if ($this->fontDescriptor != $font['fontmetrics']) {
3913 $regenerate = true;
3914 } // mPDF 6
3915
3916 if (empty($font['name']) || $font['originalsize'] != $ttfstat['size'] || $regenerate) {
3917 $generator = new MetricsGenerator($this->fontCache, $this->fontDescriptor);
3918
3919 $generator->generateMetrics(
3920 $ttffile,
3921 $ttfstat,
3922 $fontkey,
3923 $TTCfontID,
3924 $this->debugfonts,
3925 $BMPonly,
3926 $font['useOTL'],
3927 $fontUseOTL
3928 );
3929
3930 $font = $this->fontCache->jsonLoad($fontCacheFilename);
3931 $cw = $this->fontCache->load($fontkey . '.cw.dat');
3932 $glyphIDtoUni = $this->fontCache->load($fontkey . '.gid.dat');
3933 } else {
3934 if ($this->fontCache->has($fontkey . '.cw.dat')) {
3935 $cw = $this->fontCache->load($fontkey . '.cw.dat');
3936 }
3937
3938 if ($this->fontCache->has($fontkey . '.gid.dat')) {
3939 $glyphIDtoUni = $this->fontCache->load($fontkey . '.gid.dat');
3940 }
3941 }
3942
3943 if (isset($this->fontdata[$family]['sip-ext']) && $this->fontdata[$family]['sip-ext']) {
3944 $sipext = $this->fontdata[$family]['sip-ext'];
3945 } else {
3946 $sipext = '';
3947 }
3948
3949 // Override with values from config_font.php
3950 if (isset($this->fontdata[$family]['Ascent']) && $this->fontdata[$family]['Ascent']) {
3951 $desc['Ascent'] = $this->fontdata[$family]['Ascent'];
3952 }
3953 if (isset($this->fontdata[$family]['Descent']) && $this->fontdata[$family]['Descent']) {
3954 $desc['Descent'] = $this->fontdata[$family]['Descent'];
3955 }
3956 if (isset($this->fontdata[$family]['Leading']) && $this->fontdata[$family]['Leading']) {
3957 $desc['Leading'] = $this->fontdata[$family]['Leading'];
3958 }
3959
3960 $i = count($this->fonts) + $this->extraFontSubsets + 1;
3961
3962 $this->fonts[$fontkey] = [
3963 'i' => $i,
3964 'name' => $font['name'],
3965 'type' => $font['type'],
3966 'desc' => $font['desc'],
3967 'panose' => $font['panose'],
3968 'unitsPerEm' => $font['unitsPerEm'],
3969 'up' => $font['up'],
3970 'ut' => $font['ut'],
3971 'strs' => $font['strs'],
3972 'strp' => $font['strp'],
3973 'cw' => $cw,
3974 'ttffile' => $ttffile,
3975 'fontkey' => $fontkey,
3976 'used' => false,
3977 'sip' => $font['sip'],
3978 'sipext' => $sipext,
3979 'smp' => $font['smp'],
3980 'TTCfontID' => $TTCfontID,
3981 'useOTL' => $fontUseOTL,
3982 'useKashida' => (isset($this->fontdata[$family]['useKashida']) ? $this->fontdata[$family]['useKashida'] : false),
3983 'GSUBScriptLang' => $font['GSUBScriptLang'],
3984 'GSUBFeatures' => $font['GSUBFeatures'],
3985 'GSUBLookups' => $font['GSUBLookups'],
3986 'GPOSScriptLang' => $font['GPOSScriptLang'],
3987 'GPOSFeatures' => $font['GPOSFeatures'],
3988 'GPOSLookups' => $font['GPOSLookups'],
3989 'rtlPUAstr' => $font['rtlPUAstr'],
3990 'glyphIDtoUni' => $glyphIDtoUni,
3991 'haskerninfo' => $font['haskerninfo'],
3992 'haskernGPOS' => $font['haskernGPOS'],
3993 'hassmallcapsGSUB' => $font['hassmallcapsGSUB'],
3994 ];
3995
3996
3997 if (!$font['sip'] && !$font['smp']) {
3998 $subsetRange = range(32, 127);
3999 $this->fonts[$fontkey]['subset'] = array_combine($subsetRange, $subsetRange);
4000 } else {
4001 $this->fonts[$fontkey]['subsets'] = [0 => range(0, 127)];
4002 $this->fonts[$fontkey]['subsetfontids'] = [$i];
4003 }
4004
4005 if ($font['haskerninfo']) {
4006 $this->fonts[$fontkey]['kerninfo'] = $font['kerninfo'];
4007 }
4008
4009 $this->FontFiles[$fontkey] = [
4010 'length1' => $font['originalsize'],
4011 'type' => 'TTF',
4012 'ttffile' => $ttffile,
4013 'sip' => $font['sip'],
4014 'smp' => $font['smp'],
4015 ];
4016
4017 unset($cw);
4018 }
4019
4020 function SetFont($family, $style = '', $size = 0, $write = true, $forcewrite = false)
4021 {
4022 $family = strtolower($family);
4023
4024 if (!$this->onlyCoreFonts) {
4025 if ($family == 'sans' || $family == 'sans-serif') {
4026 $family = $this->sans_fonts[0];
4027 }
4028 if ($family == 'serif') {
4029 $family = $this->serif_fonts[0];
4030 }
4031 if ($family == 'mono' || $family == 'monospace') {
4032 $family = $this->mono_fonts[0];
4033 }
4034 }
4035
4036 if (isset($this->fonttrans[$family]) && $this->fonttrans[$family]) {
4037 $family = $this->fonttrans[$family];
4038 }
4039
4040 if ($family == '') {
4041 if ($this->FontFamily) {
4042 $family = $this->FontFamily;
4043 } elseif ($this->default_font) {
4044 $family = $this->default_font;
4045 } else {
4046 throw new \Mpdf\MpdfException("No font or default font set!");
4047 }
4048 }
4049
4050 $this->ReqFontStyle = $style; // required or requested style - used later for artificial bold/italic
4051
4052 if (($family == 'csymbol') || ($family == 'czapfdingbats') || ($family == 'ctimes') || ($family == 'ccourier') || ($family == 'chelvetica')) {
4053 if ($this->PDFA || $this->PDFX) {
4054 if ($family == 'csymbol' || $family == 'czapfdingbats') {
4055 throw new \Mpdf\MpdfException("Symbol and Zapfdingbats cannot be embedded in mPDF (required for PDFA1-b or PDFX/1-a).");
4056 }
4057 if ($family == 'ctimes' || $family == 'ccourier' || $family == 'chelvetica') {
4058 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
4059 $this->PDFAXwarnings[] = "Core Adobe font " . ucfirst($family) . " cannot be embedded in mPDF, which is required for PDFA1-b or PDFX/1-a. (Embedded font will be substituted.)";
4060 }
4061 if ($family == 'chelvetica') {
4062 $family = 'sans';
4063 }
4064 if ($family == 'ctimes') {
4065 $family = 'serif';
4066 }
4067 if ($family == 'ccourier') {
4068 $family = 'mono';
4069 }
4070 }
4071 $this->usingCoreFont = false;
4072 } else {
4073 $this->usingCoreFont = true;
4074 }
4075 if ($family == 'csymbol' || $family == 'czapfdingbats') {
4076 $style = '';
4077 }
4078 } else {
4079 $this->usingCoreFont = false;
4080 }
4081
4082 // mPDF 5.7.1
4083 if ($style) {
4084 $style = strtoupper($style);
4085 if ($style == 'IB') {
4086 $style = 'BI';
4087 }
4088 }
4089
4090 if (!$size) {
4091 $size = $this->FontSizePt;
4092 }
4093
4094 $fontkey = $family . $style;
4095
4096 $stylekey = $style;
4097
4098 if (!$stylekey) {
4099 $stylekey = "R";
4100 }
4101
4102 if (!$this->onlyCoreFonts && !$this->usingCoreFont) {
4103 if (!isset($this->fonts[$fontkey]) || count($this->default_available_fonts) != count($this->available_unifonts)) { // not already added
4104
4105 /* -- CJK-FONTS -- */
4106 if (in_array($fontkey, $this->available_CJK_fonts)) {
4107 if (!isset($this->fonts[$fontkey])) { // already added
4108 if (empty($this->Big5_widths)) {
4109 require __DIR__ . '/../data/CJKdata.php';
4110 }
4111 $this->AddCJKFont($family); // don't need to add style
4112 }
4113 } else { // Test to see if requested font/style is available - or substitute /* -- END CJK-FONTS -- */
4114 if (!in_array($fontkey, $this->available_unifonts)) {
4115 // If font[nostyle] exists - set it
4116 if (in_array($family, $this->available_unifonts)) {
4117 $style = '';
4118 } // elseif only one font available - set it (assumes if only one font available it will not have a style)
4119 elseif (count($this->available_unifonts) == 1) {
4120 $family = $this->available_unifonts[0];
4121 $style = '';
4122 } else {
4123 $found = 0;
4124 // else substitute font of similar type
4125 if (in_array($family, $this->sans_fonts)) {
4126 $i = array_intersect($this->sans_fonts, $this->available_unifonts);
4127 if (count($i)) {
4128 $i = array_values($i);
4129 // with requested style if possible
4130 if (!in_array(($i[0] . $style), $this->available_unifonts)) {
4131 $style = '';
4132 }
4133 $family = $i[0];
4134 $found = 1;
4135 }
4136 } elseif (in_array($family, $this->serif_fonts)) {
4137 $i = array_intersect($this->serif_fonts, $this->available_unifonts);
4138 if (count($i)) {
4139 $i = array_values($i);
4140 // with requested style if possible
4141 if (!in_array(($i[0] . $style), $this->available_unifonts)) {
4142 $style = '';
4143 }
4144 $family = $i[0];
4145 $found = 1;
4146 }
4147 } elseif (in_array($family, $this->mono_fonts)) {
4148 $i = array_intersect($this->mono_fonts, $this->available_unifonts);
4149 if (count($i)) {
4150 $i = array_values($i);
4151 // with requested style if possible
4152 if (!in_array(($i[0] . $style), $this->available_unifonts)) {
4153 $style = '';
4154 }
4155 $family = $i[0];
4156 $found = 1;
4157 }
4158 }
4159
4160 if (!$found) {
4161 // set first available font
4162 $fs = $this->available_unifonts[0];
4163 preg_match('/^([a-z_0-9\-]+)([BI]{0,2})$/', $fs, $fas); // Allow "-"
4164 // with requested style if possible
4165 $ws = $fas[1] . $style;
4166 if (in_array($ws, $this->available_unifonts)) {
4167 $family = $fas[1]; // leave $style as is
4168 } elseif (in_array($fas[1], $this->available_unifonts)) {
4169 // or without style
4170 $family = $fas[1];
4171 $style = '';
4172 } else {
4173 // or with the style specified
4174 $family = $fas[1];
4175 $style = $fas[2];
4176 }
4177 }
4178 }
4179 $fontkey = $family . $style;
4180 }
4181 }
4182 }
4183
4184 // try to add font (if not already added)
4185 $this->AddFont($family, $style);
4186
4187 // Test if font is already selected
4188 if ($this->FontFamily == $family && $this->FontFamily == $this->currentfontfamily && $this->FontStyle == $style && $this->FontStyle == $this->currentfontstyle && $this->FontSizePt == $size && $this->FontSizePt == $this->currentfontsize && !$forcewrite) {
4189 return $family;
4190 }
4191
4192 $fontkey = $family . $style;
4193
4194 // Select it
4195 $this->FontFamily = $family;
4196 $this->FontStyle = $style;
4197 $this->FontSizePt = $size;
4198 $this->FontSize = $size / Mpdf::SCALE;
4199 $this->CurrentFont = &$this->fonts[$fontkey];
4200 if ($write) {
4201 $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
4202 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
4203 $this->writer->write($fontout);
4204 }
4205 $this->pageoutput[$this->page]['Font'] = $fontout;
4206 }
4207
4208 // Added - currentfont (lowercase) used in HTML2PDF
4209 $this->currentfontfamily = $family;
4210 $this->currentfontsize = $size;
4211 $this->currentfontstyle = $style;
4212 $this->setMBencoding('UTF-8');
4213 } else { // if using core fonts
4214 if ($this->PDFA || $this->PDFX) {
4215 throw new \Mpdf\MpdfException('Core Adobe fonts cannot be embedded in mPDF (required for PDFA1-b or PDFX/1-a) - cannot use option to use core fonts.');
4216 }
4217 $this->setMBencoding('windows-1252');
4218
4219 // Test if font is already selected
4220 if (($this->FontFamily == $family) and ( $this->FontStyle == $style) and ( $this->FontSizePt == $size) && !$forcewrite) {
4221 return $family;
4222 }
4223
4224 if (!isset($this->CoreFonts[$fontkey])) {
4225 if (in_array($family, $this->serif_fonts)) {
4226 $family = 'ctimes';
4227 } elseif (in_array($family, $this->mono_fonts)) {
4228 $family = 'ccourier';
4229 } else {
4230 $family = 'chelvetica';
4231 }
4232 $this->usingCoreFont = true;
4233 $fontkey = $family . $style;
4234 }
4235
4236 if (!isset($this->fonts[$fontkey])) {
4237 // STANDARD CORE FONTS
4238 if (isset($this->CoreFonts[$fontkey])) {
4239 // Load metric file
4240 $file = $family;
4241 if ($family == 'ctimes' || $family == 'chelvetica' || $family == 'ccourier') {
4242 $file .= strtolower($style);
4243 }
4244 require __DIR__ . '/../data/font/' . $file . '.php';
4245 if (!isset($cw)) {
4246 throw new \Mpdf\MpdfException(sprintf('Could not include font metric file "%s"', $file));
4247 }
4248 $i = count($this->fonts) + $this->extraFontSubsets + 1;
4249 $this->fonts[$fontkey] = ['i' => $i, 'type' => 'core', 'name' => $this->CoreFonts[$fontkey], 'desc' => $desc, 'up' => $up, 'ut' => $ut, 'cw' => $cw];
4250 if ($this->useKerning && isset($kerninfo)) {
4251 $this->fonts[$fontkey]['kerninfo'] = $kerninfo;
4252 }
4253 } else {
4254 throw new \Mpdf\MpdfException(sprintf('Font %s not defined', $fontkey));
4255 }
4256 }
4257
4258 // Test if font is already selected
4259 if (($this->FontFamily == $family) and ( $this->FontStyle == $style) and ( $this->FontSizePt == $size) && !$forcewrite) {
4260 return $family;
4261 }
4262 // Select it
4263 $this->FontFamily = $family;
4264 $this->FontStyle = $style;
4265 $this->FontSizePt = $size;
4266 $this->FontSize = $size / Mpdf::SCALE;
4267 $this->CurrentFont = &$this->fonts[$fontkey];
4268 if ($write) {
4269 $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
4270 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
4271 $this->writer->write($fontout);
4272 }
4273 $this->pageoutput[$this->page]['Font'] = $fontout;
4274 }
4275 // Added - currentfont (lowercase) used in HTML2PDF
4276 $this->currentfontfamily = $family;
4277 $this->currentfontsize = $size;
4278 $this->currentfontstyle = $style;
4279 }
4280
4281 return $family;
4282 }
4283
4284 function SetFontSize($size, $write = true)
4285 {
4286 // Set font size in points
4287 if ($this->FontSizePt == $size) {
4288 return;
4289 }
4290 $this->FontSizePt = $size;
4291 $this->FontSize = $size / Mpdf::SCALE;
4292 $this->currentfontsize = $size;
4293 if ($write) {
4294 $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
4295 // Edited mPDF 3.0
4296 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
4297 $this->writer->write($fontout);
4298 }
4299 $this->pageoutput[$this->page]['Font'] = $fontout;
4300 }
4301 }
4302
4303 function AddLink()
4304 {
4305 // Create a new internal link
4306 $n = count($this->links) + 1;
4307 $this->links[$n] = [0, 0];
4308 return $n;
4309 }
4310
4311 function SetLink($link, $y = 0, $page = -1)
4312 {
4313 // Set destination of internal link
4314 if ($y == -1) {
4315 $y = $this->y;
4316 }
4317 if ($page == -1) {
4318 $page = $this->page;
4319 }
4320 $this->links[$link] = [$page, $y];
4321 }
4322
4323 function Link($x, $y, $w, $h, $link)
4324 {
4325 $l = [$x * Mpdf::SCALE, $this->hPt - $y * Mpdf::SCALE, $w * Mpdf::SCALE, $h * Mpdf::SCALE, $link];
4326 if ($this->keep_block_together) { // don't write yet
4327 return;
4328 } elseif ($this->table_rotate) { // *TABLES*
4329 $this->tbrot_Links[$this->page][] = $l; // *TABLES*
4330 return; // *TABLES*
4331 } // *TABLES*
4332 elseif ($this->kwt) {
4333 $this->kwt_Links[$this->page][] = $l;
4334 return;
4335 }
4336
4337 if ($this->writingHTMLheader || $this->writingHTMLfooter) {
4338 $this->HTMLheaderPageLinks[] = $l;
4339 return;
4340 }
4341 // Put a link on the page
4342 $this->PageLinks[$this->page][] = $l;
4343 // Save cross-reference to Column buffer
4344 $ref = count($this->PageLinks[$this->page]) - 1; // *COLUMNS*
4345 $this->columnLinks[$this->CurrCol][(int) $this->x][(int) $this->y] = $ref; // *COLUMNS*
4346 }
4347
4348 function Text($x, $y, $txt, $OTLdata = [], $textvar = 0, $aixextra = '', $coordsys = '', $return = false)
4349 {
4350 // Output (or return) a string
4351 // Called (internally) by Watermark() & _tableWrite() [rotated cells] & TableHeaderFooter() & WriteText()
4352 // Called also from classes/svg.php
4353 // Expects Font to be set
4354 // Expects input to be mb_encoded if necessary and RTL reversed & OTL processed
4355 // ARTIFICIAL BOLD AND ITALIC
4356 $s = 'q ';
4357 if ($this->falseBoldWeight && strpos($this->ReqFontStyle, "B") !== false && strpos($this->FontStyle, "B") === false) {
4358 $s .= '2 Tr 1 J 1 j ';
4359 $s .= sprintf('%.3F w ', ($this->FontSize / 130) * Mpdf::SCALE * $this->falseBoldWeight);
4360 $tc = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
4361 if ($this->FillColor != $tc) {
4362 $s .= $tc . ' ';
4363 } // stroke (outline) = same colour as text(fill)
4364 }
4365 if (strpos($this->ReqFontStyle, "I") !== false && strpos($this->FontStyle, "I") === false) {
4366 $aix = '1 0 0.261799 1 %.3F %.3F Tm';
4367 } else {
4368 $aix = '%.3F %.3F Td';
4369 }
4370
4371 $aix = $aixextra . $aix;
4372
4373 if ($this->ColorFlag) {
4374 $s .= $this->TextColor . ' ';
4375 }
4376
4377 $this->CurrentFont['used'] = true;
4378
4379 if ($this->usingCoreFont) {
4380 $txt2 = str_replace(chr(160), chr(32), $txt);
4381 } else {
4382 $txt2 = str_replace(chr(194) . chr(160), chr(32), $txt);
4383 }
4384
4385 $px = $x;
4386 $py = $y;
4387 if ($coordsys != 'SVG') {
4388 $px = $x * Mpdf::SCALE;
4389 $py = ($this->h - $y) * Mpdf::SCALE;
4390 }
4391
4392
4395 // IF corefonts AND NOT SmCaps AND NOT Kerning
4396 // Just output text
4397 if ($this->usingCoreFont && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING)) {
4398 $txt2 = $this->writer->escape($txt2);
4399 $s .= sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
4400 } // IF NOT corefonts [AND NO wordspacing] AND NOT SIP/SMP AND NOT SmCaps AND NOT Kerning AND NOT OTL
4401 // Just output text
4402 elseif (!$this->usingCoreFont && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING) && !(isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata['GPOSinfo']))) {
4403 // IF SIP/SMP
4404 if ($this->CurrentFont['sip'] || $this->CurrentFont['smp']) {
4405 $txt2 = $this->UTF8toSubset($txt2);
4406 $s .=sprintf('BT ' . $aix . ' %s Tj ET', $px, $py, $txt2);
4407 } // NOT SIP/SMP
4408 else {
4409 $txt2 = $this->writer->utf8ToUtf16BigEndian($txt2, false);
4410 $txt2 = $this->writer->escape($txt2);
4411 $s .=sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
4412 }
4413 } // IF NOT corefonts [AND IS wordspacing] AND NOT SIP AND NOT SmCaps AND NOT Kerning AND NOT OTL
4414 // Not required here (cf. Cell() )
4415 // ELSE (IF SmCaps || Kerning || OTL) [corefonts or not corefonts; SIP or SMP or BMP]
4416 else {
4417 $s .= $this->applyGPOSpdf($txt2, $aix, $px, $py, $OTLdata, $textvar);
4418 }
4419 /* * ************** END ************************ */
4420
4421 $s .= ' ';
4422
4423 if (($textvar & TextVars::FD_UNDERLINE) && $txt != '') { // mPDF 5.7.1
4424 $c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
4425 if ($this->FillColor != $c) {
4426 $s.= ' ' . $c . ' ';
4427 }
4428 if (isset($this->CurrentFont['up']) && $this->CurrentFont['up']) {
4429 $up = $this->CurrentFont['up'];
4430 } else {
4431 $up = -100;
4432 }
4433 $adjusty = (-$up / 1000 * $this->FontSize);
4434 if (isset($this->CurrentFont['ut']) && $this->CurrentFont['ut']) {
4435 $ut = $this->CurrentFont['ut'] / 1000 * $this->FontSize;
4436 } else {
4437 $ut = 60 / 1000 * $this->FontSize;
4438 }
4439 $olw = $this->LineWidth;
4440 $s .= ' ' . (sprintf(' %.3F w', $ut * Mpdf::SCALE));
4441 $s .= ' ' . $this->_dounderline($x, $y + $adjusty, $txt, $OTLdata, $textvar);
4442 $s .= ' ' . (sprintf(' %.3F w', $olw * Mpdf::SCALE));
4443 if ($this->FillColor != $c) {
4444 $s.= ' ' . $this->FillColor . ' ';
4445 }
4446 }
4447 // STRIKETHROUGH
4448 if (($textvar & TextVars::FD_LINETHROUGH) && $txt != '') { // mPDF 5.7.1
4449 $c = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
4450 if ($this->FillColor != $c) {
4451 $s.= ' ' . $c . ' ';
4452 }
4453 // Superscript and Subscript Y coordinate adjustment (now for striked-through texts)
4454 if (isset($this->CurrentFont['desc']['CapHeight']) && $this->CurrentFont['desc']['CapHeight']) {
4455 $ch = $this->CurrentFont['desc']['CapHeight'];
4456 } else {
4457 $ch = 700;
4458 }
4459 $adjusty = (-$ch / 1000 * $this->FontSize) * 0.35;
4460 if (isset($this->CurrentFont['ut']) && $this->CurrentFont['ut']) {
4461 $ut = $this->CurrentFont['ut'] / 1000 * $this->FontSize;
4462 } else {
4463 $ut = 60 / 1000 * $this->FontSize;
4464 }
4465 $olw = $this->LineWidth;
4466 $s .= ' ' . (sprintf(' %.3F w', $ut * Mpdf::SCALE));
4467 $s .= ' ' . $this->_dounderline($x, $y + $adjusty, $txt, $OTLdata, $textvar);
4468 $s .= ' ' . (sprintf(' %.3F w', $olw * Mpdf::SCALE));
4469 if ($this->FillColor != $c) {
4470 $s.= ' ' . $this->FillColor . ' ';
4471 }
4472 }
4473 $s .= 'Q';
4474
4475 if ($return) {
4476 return $s . " \n";
4477 }
4478 $this->writer->write($s);
4479 }
4480
4481 /* -- DIRECTW -- */
4482
4483 function WriteText($x, $y, $txt)
4484 {
4485 // Output a string using Text() but does encoding and text reversing of RTL
4486 $txt = $this->purify_utf8_text($txt);
4487 if ($this->text_input_as_HTML) {
4488 $txt = $this->all_entities_to_utf8($txt);
4489 }
4490 if ($this->usingCoreFont) {
4491 $txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
4492 }
4493
4494 // DIRECTIONALITY
4495 if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
4496 $this->biDirectional = true;
4497 } // *OTL*
4498
4499 $textvar = 0;
4500 $save_OTLtags = $this->OTLtags;
4501 $this->OTLtags = [];
4502 if ($this->useKerning) {
4503 if ($this->CurrentFont['haskernGPOS']) {
4504 $this->OTLtags['Plus'] .= ' kern';
4505 } else {
4506 $textvar = ($textvar | TextVars::FC_KERNING);
4507 }
4508 }
4509
4510 /* -- OTL -- */
4511 // Use OTL OpenType Table Layout - GSUB & GPOS
4512 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
4513 $txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
4514 $OTLdata = $this->otl->OTLdata;
4515 }
4516 /* -- END OTL -- */
4517 $this->OTLtags = $save_OTLtags;
4518
4519 $this->magic_reverse_dir($txt, $this->directionality, $OTLdata);
4520
4521 $this->Text($x, $y, $txt, $OTLdata, $textvar);
4522 }
4523
4524 function WriteCell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = 0, $link = '', $currentx = 0)
4525 {
4526 // Output a cell using Cell() but does encoding and text reversing of RTL
4527 $txt = $this->purify_utf8_text($txt);
4528 if ($this->text_input_as_HTML) {
4529 $txt = $this->all_entities_to_utf8($txt);
4530 }
4531 if ($this->usingCoreFont) {
4532 $txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
4533 }
4534 // DIRECTIONALITY
4535 if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
4536 $this->biDirectional = true;
4537 } // *OTL*
4538
4539 $textvar = 0;
4540 $save_OTLtags = $this->OTLtags;
4541 $this->OTLtags = [];
4542 if ($this->useKerning) {
4543 if ($this->CurrentFont['haskernGPOS']) {
4544 $this->OTLtags['Plus'] .= ' kern';
4545 } else {
4546 $textvar = ($textvar | TextVars::FC_KERNING);
4547 }
4548 }
4549
4550 /* -- OTL -- */
4551 // Use OTL OpenType Table Layout - GSUB & GPOS
4552 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
4553 $txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
4554 $OTLdata = $this->otl->OTLdata;
4555 }
4556 /* -- END OTL -- */
4557 $this->OTLtags = $save_OTLtags;
4558
4559 $this->magic_reverse_dir($txt, $this->directionality, $OTLdata);
4560
4561 $this->Cell($w, $h, $txt, $border, $ln, $align, $fill, $link, $currentx, 0, 0, 'M', 0, false, $OTLdata, $textvar);
4562 }
4563
4564 /* -- END DIRECTW -- */
4565
4566 function ResetSpacing()
4567 {
4568 if ($this->ws != 0) {
4569 $this->writer->write('BT 0 Tw ET');
4570 }
4571 $this->ws = 0;
4572 if ($this->charspacing != 0) {
4573 $this->writer->write('BT 0 Tc ET');
4574 }
4575 $this->charspacing = 0;
4576 }
4577
4578 function SetSpacing($cs, $ws)
4579 {
4580 if (intval($cs * 1000) == 0) {
4581 $cs = 0;
4582 }
4583 if ($cs) {
4584 $this->writer->write(sprintf('BT %.3F Tc ET', $cs));
4585 } elseif ($this->charspacing != 0) {
4586 $this->writer->write('BT 0 Tc ET');
4587 }
4588 $this->charspacing = $cs;
4589 if (intval($ws * 1000) == 0) {
4590 $ws = 0;
4591 }
4592 if ($ws) {
4593 $this->writer->write(sprintf('BT %.3F Tw ET', $ws));
4594 } elseif ($this->ws != 0) {
4595 $this->writer->write('BT 0 Tw ET');
4596 }
4597 $this->ws = $ws;
4598 }
4599
4600 // WORD SPACING
4601 function GetJspacing($nc, $ns, $w, $inclCursive, &$cOTLdata)
4602 {
4603 $kashida_present = false;
4604 $kashida_space = 0;
4605 if ($w > 0 && $inclCursive && isset($this->CurrentFont['useKashida']) && $this->CurrentFont['useKashida'] && !empty($cOTLdata)) {
4606 for ($c = 0; $c < count($cOTLdata); $c++) {
4607 for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
4608 if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
4609 $kashida_present = true;
4610 break 2;
4611 }
4612 }
4613 }
4614 }
4615
4616 if ($kashida_present) {
4617 $k_ctr = 0; // Number of kashida points
4618 $k_total = 0; // Total of kashida values (priority)
4619 // Reset word
4620 $max_kashida_in_word = 0;
4621 $last_kashida_in_word = -1;
4622
4623 for ($c = 0; $c < count($cOTLdata); $c++) {
4624 for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
4625 if ($cOTLdata[$c]['group'][$i] == 'S') {
4626 // Save from last word
4627 if ($max_kashida_in_word) {
4628 $k_ctr++;
4629 $k_total = $max_kashida_in_word;
4630 }
4631 // Reset word
4632 $max_kashida_in_word = 0;
4633 $last_kashida_in_word = -1;
4634 }
4635
4636 if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
4637 if ($max_kashida_in_word) {
4638 if ($cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > $max_kashida_in_word) {
4639 $max_kashida_in_word = $cOTLdata[$c]['GPOSinfo'][$i]['kashida'];
4640 $cOTLdata[$c]['GPOSinfo'][$last_kashida_in_word]['kashida'] = 0;
4641 $last_kashida_in_word = $i;
4642 } else {
4643 $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] = 0;
4644 }
4645 } else {
4646 $max_kashida_in_word = $cOTLdata[$c]['GPOSinfo'][$i]['kashida'];
4647 $last_kashida_in_word = $i;
4648 }
4649 }
4650 }
4651 }
4652 // Save from last word
4653 if ($max_kashida_in_word) {
4654 $k_ctr++;
4655 $k_total = $max_kashida_in_word;
4656 }
4657
4658 // Number of kashida points = $k_ctr
4659 // $useKashida is a % value from CurrentFont/config_fonts.php
4660 // % ratio divided between word-spacing and kashida-spacing
4661 $kashida_space_ratio = intval($this->CurrentFont['useKashida']) / 100;
4662
4663
4664 $kashida_space = $w * $kashida_space_ratio;
4665
4666 $tatw = $this->_getCharWidth($this->CurrentFont['cw'], 0x0640);
4667 // Only use kashida if each allocated kashida width is > 0.01 x width of a tatweel
4668 // Otherwise fontstretch is too small and errors
4669 // If not just leave to adjust word-spacing
4670 if ($tatw && (($kashida_space / $k_ctr) / $tatw) > 0.01) {
4671 for ($c = 0; $c < count($cOTLdata); $c++) {
4672 for ($i = 0; $i < strlen($cOTLdata[$c]['group']); $i++) {
4673 if (isset($cOTLdata[$c]['GPOSinfo'][$i]['kashida']) && $cOTLdata[$c]['GPOSinfo'][$i]['kashida'] > 0) {
4674 // At this point kashida is a number representing priority (higher number - higher priority)
4675 // We are now going to set it as an actual length
4676 // This shares it equally amongst words:
4677 $cOTLdata[$c]['GPOSinfo'][$i]['kashida_space'] = (1 / $k_ctr) * $kashida_space;
4678 }
4679 }
4680 }
4681 $w -= $kashida_space;
4682 }
4683 }
4684
4685 $ws = 0;
4686 $charspacing = 0;
4687 $ww = $this->jSWord;
4688 $ncx = $nc - 1;
4689 if ($nc == 0) {
4690 return [0, 0, 0];
4691 } // Only word spacing allowed / possible
4692 elseif ($this->fixedlSpacing !== false || $inclCursive) {
4693 if ($ns) {
4694 $ws = $w / $ns;
4695 }
4696 } elseif ($nc == 1) {
4697 $charspacing = $w;
4698 } elseif (!$ns) {
4699 $charspacing = $w / ($ncx );
4700 if (($this->jSmaxChar > 0) && ($charspacing > $this->jSmaxChar)) {
4701 $charspacing = $this->jSmaxChar;
4702 }
4703 } elseif ($ns == ($ncx )) {
4704 $charspacing = $w / $ns;
4705 } else {
4706 if ($this->usingCoreFont) {
4707 $cs = ($w * (1 - $this->jSWord)) / ($ncx );
4708 if (($this->jSmaxChar > 0) && ($cs > $this->jSmaxChar)) {
4709 $cs = $this->jSmaxChar;
4710 $ww = 1 - (($cs * ($ncx )) / $w);
4711 }
4712 $charspacing = $cs;
4713 $ws = ($w * ($ww) ) / $ns;
4714 } else {
4715 $cs = ($w * (1 - $this->jSWord)) / ($ncx - $ns);
4716 if (($this->jSmaxChar > 0) && ($cs > $this->jSmaxChar)) {
4717 $cs = $this->jSmaxChar;
4718 $ww = 1 - (($cs * ($ncx - $ns)) / $w);
4719 }
4720 $charspacing = $cs;
4721 $ws = (($w * ($ww) ) / $ns) - $charspacing;
4722 }
4723 }
4724 return [$charspacing, $ws, $kashida_space];
4725 }
4726
4734 function Cell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = '', $fill = 0, $link = '', $currentx = 0, $lcpaddingL = 0, $lcpaddingR = 0, $valign = 'M', $spanfill = 0, $exactWidth = false, $OTLdata = false, $textvar = 0, $lineBox = false)
4735 {
4736 // NON_BREAKING SPACE
4737 if ($this->usingCoreFont) {
4738 $txt = str_replace(chr(160), chr(32), $txt);
4739 } else {
4740 $txt = str_replace(chr(194) . chr(160), chr(32), $txt);
4741 }
4742
4743 $oldcolumn = $this->CurrCol;
4744
4745 // Automatic page break
4746 // Allows PAGE-BREAK-AFTER = avoid to work
4747 if (isset($this->blk[$this->blklvl])) {
4748 $bottom = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['margin_bottom'];
4749 } else {
4750 $bottom = 0;
4751 }
4752
4753 if (!$this->tableLevel
4754 && (
4755 ($this->y + $this->divheight > $this->PageBreakTrigger)
4756 || ($this->y + $h > $this->PageBreakTrigger)
4757 || (
4758 $this->y + ($h * 2) + $bottom > $this->PageBreakTrigger
4759 && $this->blk[$this->blklvl]['page_break_after_avoid']
4760 )
4761 )
4762 && !$this->InFooter
4763 && $this->AcceptPageBreak()
4764 ) { // mPDF 5.7.2
4765
4766 $x = $this->x; // Current X position
4767
4768 // WORD SPACING
4769 $ws = $this->ws; // Word Spacing
4770 $charspacing = $this->charspacing; // Character Spacing
4771 $this->ResetSpacing();
4772
4773 $this->AddPage($this->CurOrientation);
4774
4775 // Added to correct for OddEven Margins
4776 $x += $this->MarginCorrection;
4777 if ($currentx) {
4778 $currentx += $this->MarginCorrection;
4779 }
4780 $this->x = $x;
4781 // WORD SPACING
4782 $this->SetSpacing($charspacing, $ws);
4783 }
4784
4785 // Test: to put line through centre of cell: $this->Line($this->x,$this->y+($h/2),$this->x+50,$this->y+($h/2));
4786 // Test: to put border around cell as it is specified: $border='LRTB';
4787
4788 /* -- COLUMNS -- */
4789 // COLS
4790 // COLUMN CHANGE
4791 if ($this->CurrCol != $oldcolumn) {
4792 if ($currentx) {
4793 $currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
4794 }
4795 $this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
4796 }
4797
4798 // COLUMNS Update/overwrite the lowest bottom of printing y value for a column
4799 if ($this->ColActive) {
4800 if ($h) {
4801 $this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $h;
4802 } else {
4803 $this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $this->divheight;
4804 }
4805 }
4806 /* -- END COLUMNS -- */
4807
4808
4809 if ($w == 0) {
4810 $w = $this->w - $this->rMargin - $this->x;
4811 }
4812
4813 $s = '';
4814 if ($fill == 1 && $this->FillColor) {
4815 if ((isset($this->pageoutput[$this->page]['FillColor']) && $this->pageoutput[$this->page]['FillColor'] != $this->FillColor) || !isset($this->pageoutput[$this->page]['FillColor'])) {
4816 $s .= $this->FillColor . ' ';
4817 }
4818 $this->pageoutput[$this->page]['FillColor'] = $this->FillColor;
4819 }
4820
4821 if ($lineBox && isset($lineBox['boxtop']) && $txt) { // i.e. always from WriteFlowingBlock/finishFlowingBlock (but not objects -
4822 // which only have $lineBox['top'] set)
4823 $boxtop = $this->y + $lineBox['boxtop'];
4824 $boxbottom = $this->y + $lineBox['boxbottom'];
4825 $glyphYorigin = $lineBox['glyphYorigin'];
4826 $baseline_shift = $lineBox['baseline-shift'];
4827 $bord_boxtop = $bg_boxtop = $boxtop = $boxtop - $baseline_shift;
4828 $bord_boxbottom = $bg_boxbottom = $boxbottom = $boxbottom - $baseline_shift;
4829 $bord_boxheight = $bg_boxheight = $boxheight = $boxbottom - $boxtop;
4830
4831 // If inline element BACKGROUND has bounding box set by parent element:
4832 if (isset($lineBox['background-boxtop'])) {
4833 $bg_boxtop = $this->y + $lineBox['background-boxtop'] - $lineBox['background-baseline-shift'];
4834 $bg_boxbottom = $this->y + $lineBox['background-boxbottom'] - $lineBox['background-baseline-shift'];
4835 $bg_boxheight = $bg_boxbottom - $bg_boxtop;
4836 }
4837 // If inline element BORDER has bounding box set by parent element:
4838 if (isset($lineBox['border-boxtop'])) {
4839 $bord_boxtop = $this->y + $lineBox['border-boxtop'] - $lineBox['border-baseline-shift'];
4840 $bord_boxbottom = $this->y + $lineBox['border-boxbottom'] - $lineBox['border-baseline-shift'];
4841 $bord_boxheight = $bord_boxbottom - $bord_boxtop;
4842 }
4843
4844 } else {
4845
4846 $boxtop = $this->y;
4847 $boxheight = $h;
4848 $boxbottom = $this->y + $h;
4849 $baseline_shift = 0;
4850
4851 if ($txt != '') {
4852
4853 // FONT SIZE - this determines the baseline caculation
4854 $bfs = $this->FontSize;
4855 // Calculate baseline Superscript and Subscript Y coordinate adjustment
4856 $bfx = $this->baselineC;
4857 $baseline = $bfx * $bfs;
4858
4859 if ($textvar & TextVars::FA_SUPERSCRIPT) {
4860 $baseline_shift = $this->textparam['text-baseline'];
4861 } elseif ($textvar & TextVars::FA_SUBSCRIPT) {
4862 $baseline_shift = $this->textparam['text-baseline'];
4863 } elseif ($this->bullet) {
4864 $baseline += ($bfx - 0.7) * $this->FontSize;
4865 }
4866
4867 // Vertical align (for Images)
4868 if ($valign == 'T') {
4869 $va = (0.5 * $bfs * $this->normalLineheight);
4870 } elseif ($valign == 'B') {
4871 $va = $h - (0.5 * $bfs * $this->normalLineheight);
4872 } else {
4873 $va = 0.5 * $h;
4874 } // Middle
4875
4876 // ONLY SET THESE IF WANT TO CONFINE BORDER +/- FILL TO FIT FONTSIZE - NOT FULL CELL AS IS ORIGINAL FUNCTION
4877 // spanfill or spanborder are set in FlowingBlock functions
4878 if ($spanfill || !empty($this->spanborddet) || $link != '') {
4879 $exth = 0.2; // Add to fontsize to increase height of background / link / border
4880 $boxtop = $this->y + $baseline + $va - ($this->FontSize * (1 + $exth / 2) * (0.5 + $bfx));
4881 $boxheight = $this->FontSize * (1 + $exth);
4882 $boxbottom = $boxtop + $boxheight;
4883 }
4884
4885 $glyphYorigin = $baseline + $va;
4886 }
4887
4888 $boxtop -= $baseline_shift;
4889 $boxbottom -= $baseline_shift;
4890 $bord_boxtop = $bg_boxtop = $boxtop;
4891 $bord_boxbottom = $bg_boxbottom = $boxbottom;
4892 $bord_boxheight = $bg_boxheight = $boxheight = $boxbottom - $boxtop;
4893 }
4894
4895 $bbw = $tbw = $lbw = $rbw = 0; // Border widths
4896 if (!empty($this->spanborddet)) {
4897
4898 if (!isset($this->spanborddet['B'])) {
4899 $this->spanborddet['B'] = ['s' => 0, 'style' => '', 'w' => 0];
4900 }
4901
4902 if (!isset($this->spanborddet['T'])) {
4903 $this->spanborddet['T'] = ['s' => 0, 'style' => '', 'w' => 0];
4904 }
4905
4906 if (!isset($this->spanborddet['L'])) {
4907 $this->spanborddet['L'] = ['s' => 0, 'style' => '', 'w' => 0];
4908 }
4909
4910 if (!isset($this->spanborddet['R'])) {
4911 $this->spanborddet['R'] = ['s' => 0, 'style' => '', 'w' => 0];
4912 }
4913
4914 $bbw = $this->spanborddet['B']['w'];
4915 $tbw = $this->spanborddet['T']['w'];
4916 $lbw = $this->spanborddet['L']['w'];
4917 $rbw = $this->spanborddet['R']['w'];
4918 }
4919
4920 if ($fill == 1 || $border == 1 || !empty($this->spanborddet)) {
4921
4922 if (!empty($this->spanborddet)) {
4923
4924 if ($fill == 1) {
4925 $s .= sprintf('%.3F %.3F %.3F %.3F re f ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bg_boxtop + $tbw) * Mpdf::SCALE, ($w + $lbw + $rbw) * Mpdf::SCALE, (-$bg_boxheight - $tbw - $bbw) * Mpdf::SCALE);
4926 }
4927
4928 $s.= ' q ';
4929 $dashon = 3;
4930 $dashoff = 3.5;
4931 $dot = 2.5;
4932
4933 if ($tbw) {
4934 $short = 0;
4935
4936 if ($this->spanborddet['T']['style'] == 'dashed') {
4937 $s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $tbw * $dashon * Mpdf::SCALE, $tbw * $dashoff * Mpdf::SCALE);
4938 } elseif ($this->spanborddet['T']['style'] == 'dotted') {
4939 $s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $tbw * $dot * Mpdf::SCALE, -$tbw / 2 * Mpdf::SCALE);
4940 $short = $tbw / 2;
4941 } else {
4942 $s .= ' 0 j 0 J [] 0 d ';
4943 }
4944
4945 if ($this->spanborddet['T']['style'] != 'dotted') {
4946 $s .= 'q ';
4947 $s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
4948 $s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
4949 $s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
4950 $s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
4951 $s .= ' h W n '; // Ends path no-op & Sets the clipping path
4952 }
4953
4954 $c = $this->SetDColor($this->spanborddet['T']['c'], true);
4955
4956 if ($this->spanborddet['T']['style'] == 'double') {
4957 $s .= sprintf(' %s %.3F w ', $c, $tbw / 3 * Mpdf::SCALE);
4958 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw * 5 / 6) * Mpdf::SCALE, ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw * 5 / 6) * Mpdf::SCALE);
4959 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 6) * Mpdf::SCALE, ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 6) * Mpdf::SCALE);
4960 } elseif ($this->spanborddet['T']['style'] == 'dotted') {
4961 $s .= sprintf(' %s %.3F w ', $c, $tbw * Mpdf::SCALE);
4962 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 2) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 2) * Mpdf::SCALE);
4963 } else {
4964 $s .= sprintf(' %s %.3F w ', $c, $tbw * Mpdf::SCALE);
4965 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 2) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw / 2) * Mpdf::SCALE);
4966 }
4967
4968 if ($this->spanborddet['T']['style'] != 'dotted') {
4969 $s .= ' Q ';
4970 }
4971 }
4972 if ($bbw) {
4973
4974 $short = 0;
4975 if ($this->spanborddet['B']['style'] == 'dashed') {
4976 $s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $bbw * $dashon * Mpdf::SCALE, $bbw * $dashoff * Mpdf::SCALE);
4977 } elseif ($this->spanborddet['B']['style'] == 'dotted') {
4978 $s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $bbw * $dot * Mpdf::SCALE, -$bbw / 2 * Mpdf::SCALE);
4979 $short = $bbw / 2;
4980 } else {
4981 $s .= ' 0 j 0 J [] 0 d ';
4982 }
4983
4984 if ($this->spanborddet['B']['style'] != 'dotted') {
4985 $s .= 'q ';
4986 $s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
4987 $s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
4988 $s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
4989 $s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
4990 $s .= ' h W n '; // Ends path no-op & Sets the clipping path
4991 }
4992
4993 $c = $this->SetDColor($this->spanborddet['B']['c'], true);
4994
4995 if ($this->spanborddet['B']['style'] == 'double') {
4996 $s .= sprintf(' %s %.3F w ', $c, $bbw / 3 * Mpdf::SCALE);
4997 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 6) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 6) * Mpdf::SCALE);
4998 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw * 5 / 6) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw * 5 / 6) * Mpdf::SCALE);
4999 } elseif ($this->spanborddet['B']['style'] == 'dotted') {
5000 $s .= sprintf(' %s %.3F w ', $c, $bbw * Mpdf::SCALE);
5001 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 2) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 2) * Mpdf::SCALE);
5002 } else {
5003 $s .= sprintf(' %s %.3F w ', $c, $bbw * Mpdf::SCALE);
5004 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 2) * Mpdf::SCALE, ($this->x + $w + $rbw - $short) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw / 2) * Mpdf::SCALE);
5005 }
5006
5007 if ($this->spanborddet['B']['style'] != 'dotted') {
5008 $s .= ' Q ';
5009 }
5010 }
5011
5012 if ($lbw) {
5013 $short = 0;
5014 if ($this->spanborddet['L']['style'] == 'dashed') {
5015 $s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $lbw * $dashon * Mpdf::SCALE, $lbw * $dashoff * Mpdf::SCALE);
5016 } elseif ($this->spanborddet['L']['style'] == 'dotted') {
5017 $s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $lbw * $dot * Mpdf::SCALE, -$lbw / 2 * Mpdf::SCALE);
5018 $short = $lbw / 2;
5019 } else {
5020 $s .= ' 0 j 0 J [] 0 d ';
5021 }
5022
5023 if ($this->spanborddet['L']['style'] != 'dotted') {
5024 $s .= 'q ';
5025 $s .= sprintf('%.3F %.3F m ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
5026 $s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
5027 $s .= sprintf('%.3F %.3F l ', ($this->x) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
5028 $s .= sprintf('%.3F %.3F l ', ($this->x - $lbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
5029 $s .= ' h W n '; // Ends path no-op & Sets the clipping path
5030 }
5031
5032 $c = $this->SetDColor($this->spanborddet['L']['c'], true);
5033 if ($this->spanborddet['L']['style'] == 'double') {
5034 $s .= sprintf(' %s %.3F w ', $c, $lbw / 3 * Mpdf::SCALE);
5035 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw / 6) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x - $lbw / 6) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5036 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw * 5 / 6) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x - $lbw * 5 / 6) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5037 } elseif ($this->spanborddet['L']['style'] == 'dotted') {
5038 $s .= sprintf(' %s %.3F w ', $c, $lbw * Mpdf::SCALE);
5039 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x - $lbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5040 } else {
5041 $s .= sprintf(' %s %.3F w ', $c, $lbw * Mpdf::SCALE);
5042 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x - $lbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x - $lbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5043 }
5044
5045 if ($this->spanborddet['L']['style'] != 'dotted') {
5046 $s .= ' Q ';
5047 }
5048 }
5049
5050 if ($rbw) {
5051
5052 $short = 0;
5053 if ($this->spanborddet['R']['style'] == 'dashed') {
5054 $s .= sprintf(' 0 j 0 J [%.3F %.3F] 0 d ', $rbw * $dashon * Mpdf::SCALE, $rbw * $dashoff * Mpdf::SCALE);
5055 } elseif ($this->spanborddet['R']['style'] == 'dotted') {
5056 $s .= sprintf(' 1 j 1 J [%.3F %.3F] %.3F d ', 0.001, $rbw * $dot * Mpdf::SCALE, -$rbw / 2 * Mpdf::SCALE);
5057 $short = $rbw / 2;
5058 } else {
5059 $s .= ' 0 j 0 J [] 0 d ';
5060 }
5061
5062 if ($this->spanborddet['R']['style'] != 'dotted') {
5063 $s .= 'q ';
5064 $s .= sprintf('%.3F %.3F m ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw) * Mpdf::SCALE);
5065 $s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxbottom) * Mpdf::SCALE);
5066 $s .= sprintf('%.3F %.3F l ', ($this->x + $w) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
5067 $s .= sprintf('%.3F %.3F l ', ($this->x + $w + $rbw) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE);
5068 $s .= ' h W n '; // Ends path no-op & Sets the clipping path
5069 }
5070
5071 $c = $this->SetDColor($this->spanborddet['R']['c'], true);
5072 if ($this->spanborddet['R']['style'] == 'double') {
5073 $s .= sprintf(' %s %.3F w ', $c, $rbw / 3 * Mpdf::SCALE);
5074 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw / 6) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x + $w + $rbw / 6) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5075 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw * 5 / 6) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x + $w + $rbw * 5 / 6) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5076 } elseif ($this->spanborddet['R']['style'] == 'dotted') {
5077 $s .= sprintf(' %s %.3F w ', $c, $rbw * Mpdf::SCALE);
5078 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x + $w + $rbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5079 } else {
5080 $s .= sprintf(' %s %.3F w ', $c, $rbw * Mpdf::SCALE);
5081 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($this->x + $w + $rbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxtop + $tbw) * Mpdf::SCALE, ($this->x + $w + $rbw / 2) * Mpdf::SCALE, ($this->h - $bord_boxbottom - $bbw + $short) * Mpdf::SCALE);
5082 }
5083
5084 if ($this->spanborddet['R']['style'] != 'dotted') {
5085 $s .= ' Q ';
5086 }
5087 }
5088
5089 $s.= ' Q ';
5090
5091 } else { // If "border", does not come from WriteFlowingBlock or FinishFlowingBlock
5092
5093 if ($fill == 1) {
5094 $op = ($border == 1) ? 'B' : 'f';
5095 } else {
5096 $op = 'S';
5097 }
5098
5099 $s .= sprintf('%.3F %.3F %.3F %.3F re %s ', $this->x * Mpdf::SCALE, ($this->h - $bg_boxtop) * Mpdf::SCALE, $w * Mpdf::SCALE, -$bg_boxheight * Mpdf::SCALE, $op);
5100 }
5101 }
5102
5103 if (is_string($border)) { // If "border", does not come from WriteFlowingBlock or FinishFlowingBlock
5104
5105 $x = $this->x;
5106 $y = $this->y;
5107
5108 if (is_int(strpos($border, 'L'))) {
5109 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', $x * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($bord_boxbottom)) * Mpdf::SCALE);
5110 }
5111
5112 if (is_int(strpos($border, 'T'))) {
5113 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', $x * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE, ($x + $w) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE);
5114 }
5115
5116 if (is_int(strpos($border, 'R'))) {
5117 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', ($x + $w) * Mpdf::SCALE, ($this->h - $bord_boxtop) * Mpdf::SCALE, ($x + $w) * Mpdf::SCALE, ($this->h - ($bord_boxbottom)) * Mpdf::SCALE);
5118 }
5119
5120 if (is_int(strpos($border, 'B'))) {
5121 $s .= sprintf('%.3F %.3F m %.3F %.3F l S ', $x * Mpdf::SCALE, ($this->h - ($bord_boxbottom)) * Mpdf::SCALE, ($x + $w) * Mpdf::SCALE, ($this->h - ($bord_boxbottom)) * Mpdf::SCALE);
5122 }
5123 }
5124
5125 if ($txt != '') {
5126
5127 if ($exactWidth) {
5128 $stringWidth = $w;
5129 } else {
5130 $stringWidth = $this->GetStringWidth($txt, true, $OTLdata, $textvar) + ( $this->charspacing * mb_strlen($txt, $this->mb_enc) / Mpdf::SCALE ) + ( $this->ws * mb_substr_count($txt, ' ', $this->mb_enc) / Mpdf::SCALE );
5131 }
5132
5133 // Set x OFFSET FOR PRINTING
5134 if ($align == 'R') {
5135 $dx = $w - $this->cMarginR - $stringWidth - $lcpaddingR;
5136 } elseif ($align == 'C') {
5137 $dx = (($w - $stringWidth ) / 2);
5138 } elseif ($align == 'L' or $align == 'J') {
5139 $dx = $this->cMarginL + $lcpaddingL;
5140 } else {
5141 $dx = 0;
5142 }
5143
5144 if ($this->ColorFlag) {
5145 $s .='q ' . $this->TextColor . ' ';
5146 }
5147
5148 // OUTLINE
5149 if (isset($this->textparam['outline-s']) && $this->textparam['outline-s'] && !($textvar & TextVars::FC_SMALLCAPS)) { // mPDF 5.7.1
5150 $s .=' ' . sprintf('%.3F w', $this->LineWidth * Mpdf::SCALE) . ' ';
5151 $s .=" $this->DrawColor ";
5152 $s .=" 2 Tr ";
5153 } elseif ($this->falseBoldWeight && strpos($this->ReqFontStyle, "B") !== false && strpos($this->FontStyle, "B") === false && !($textvar & TextVars::FC_SMALLCAPS)) { // can't use together with OUTLINE or Small Caps // mPDF 5.7.1 ??? why not with SmallCaps ???
5154 $s .= ' 2 Tr 1 J 1 j ';
5155 $s .= ' ' . sprintf('%.3F w', ($this->FontSize / 130) * Mpdf::SCALE * $this->falseBoldWeight) . ' ';
5156 $tc = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
5157 if ($this->FillColor != $tc) {
5158 $s .= ' ' . $tc . ' ';
5159 } // stroke (outline) = same colour as text(fill)
5160 } else {
5161 $s .=" 0 Tr ";
5162 }
5163
5164 if (strpos($this->ReqFontStyle, "I") !== false && strpos($this->FontStyle, "I") === false) { // Artificial italic
5165 $aix = '1 0 0.261799 1 %.3F %.3F Tm ';
5166 } else {
5167 $aix = '%.3F %.3F Td ';
5168 }
5169
5170 $px = ($this->x + $dx) * Mpdf::SCALE;
5171 $py = ($this->h - ($this->y + $glyphYorigin - $baseline_shift)) * Mpdf::SCALE;
5172
5173 // THE TEXT
5174 $txt2 = $txt;
5175 $sub = '';
5176 $this->CurrentFont['used'] = true;
5177
5178 /* * ************** SIMILAR TO Text() ************************ */
5179
5180 // IF corefonts AND NOT SmCaps AND NOT Kerning
5181 // Just output text; charspacing and wordspacing already set by charspacing (Tc) and ws (Tw)
5182 if ($this->usingCoreFont && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING)) {
5183 $txt2 = $this->writer->escape($txt2);
5184 $sub .= sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
5185 } // IF NOT corefonts AND NO wordspacing AND NOT SIP/SMP AND NOT SmCaps AND NOT Kerning AND NOT OTL
5186 // Just output text
5187 elseif (!$this->usingCoreFont && !$this->ws && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING) && !(isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && !empty($OTLdata['GPOSinfo']))) {
5188 // IF SIP/SMP
5189 if ((isset($this->CurrentFont['sip']) && $this->CurrentFont['sip']) || (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp'])) {
5190 $txt2 = $this->UTF8toSubset($txt2);
5191 $sub .=sprintf('BT ' . $aix . ' %s Tj ET', $px, $py, $txt2);
5192 } // NOT SIP/SMP
5193 else {
5194 $txt2 = $this->writer->utf8ToUtf16BigEndian($txt2, false);
5195 $txt2 = $this->writer->escape($txt2);
5196 $sub .=sprintf('BT ' . $aix . ' (%s) Tj ET', $px, $py, $txt2);
5197 }
5198 } // IF NOT corefonts AND IS wordspacing AND NOT SIP AND NOT SmCaps AND NOT Kerning AND NOT OTL
5199 // Output text word by word with an adjustment to the intercharacter spacing for SPACEs to form word spacing
5200 // IF multibyte - Tw has no effect - need to do word spacing using an adjustment before each space
5201 elseif (!$this->usingCoreFont && $this->ws && !((isset($this->CurrentFont['sip']) && $this->CurrentFont['sip']) || (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp'])) && !($textvar & TextVars::FC_SMALLCAPS) && !($textvar & TextVars::FC_KERNING) && !(isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF) && (!empty($OTLdata['GPOSinfo']) || (strpos($OTLdata['group'], 'M') !== false && $this->charspacing)) )) {
5202 $space = " ";
5203 $space = $this->writer->utf8ToUtf16BigEndian($space, false);
5204 $space = $this->writer->escape($space);
5205 $sub .=sprintf('BT ' . $aix . ' %.3F Tc [', $px, $py, $this->charspacing);
5206 $t = explode(' ', $txt2);
5207 $numt = count($t);
5208 for ($i = 0; $i < $numt; $i++) {
5209 $tx = $t[$i];
5210 $tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
5211 $tx = $this->writer->escape($tx);
5212 $sub .=sprintf('(%s) ', $tx);
5213 if (($i + 1) < $numt) {
5214 $adj = -($this->ws) * 1000 / $this->FontSizePt;
5215 $sub .=sprintf('%d(%s) ', $adj, $space);
5216 }
5217 }
5218 $sub .='] TJ ';
5219 $sub .=' ET';
5220 } // ELSE (IF SmCaps || Kerning || OTL) [corefonts or not corefonts; SIP or SMP or BMP]
5221 else {
5222 $sub = $this->applyGPOSpdf($txt, $aix, $px, $py, $OTLdata, $textvar);
5223 }
5224
5227 if ($this->shrin_k > 1) {
5228 $shrin_k = $this->shrin_k;
5229 } else {
5230 $shrin_k = 1;
5231 }
5232
5233 // UNDERLINE
5234 if ($textvar & TextVars::FD_UNDERLINE) { // mPDF 5.7.1 // mPDF 6
5235
5236 // mPDF 5.7.3 inline text-decoration parameters
5237
5238 $c = isset($this->textparam['u-decoration']['color']) ? $this->textparam['u-decoration']['color'] : '';
5239 if ($this->FillColor != $c) {
5240 $sub .= ' ' . $c . ' ';
5241 }
5242
5243 // mPDF 5.7.3 inline text-decoration parameters
5244 $decorationfontkey = isset($this->textparam['u-decoration']['fontkey']) ? $this->textparam['u-decoration']['fontkey'] : '';
5245 $decorationfontsize = isset($this->textparam['u-decoration']['fontsize']) ? $this->textparam['u-decoration']['fontsize'] / $shrin_k : 0;
5246
5247 if (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
5248 $ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
5249 } else {
5250 $ut = 60 / 1000 * $decorationfontsize;
5251 }
5252
5253 if (isset($this->fonts[$decorationfontkey]['up']) && $this->fonts[$decorationfontkey]['up']) {
5254 $up = $this->fonts[$decorationfontkey]['up'];
5255 } else {
5256 $up = -100;
5257 }
5258
5259 $adjusty = (-$up / 1000 * $decorationfontsize) + $ut / 2;
5260 $ubaseline = isset($this->textparam['u-decoration']['baseline'])
5261 ? $glyphYorigin - $this->textparam['u-decoration']['baseline'] / $shrin_k
5262 : $glyphYorigin;
5263
5264 $olw = $this->LineWidth;
5265
5266 $sub .= ' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * Mpdf::SCALE));
5267 $sub .= ' ' . $this->_dounderline($this->x + $dx, $this->y + $ubaseline + $adjusty, $txt, $OTLdata, $textvar);
5268 $sub .= ' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * Mpdf::SCALE));
5269
5270 if ($this->FillColor != $c) {
5271 $sub .= ' ' . $this->FillColor . ' ';
5272 }
5273 }
5274
5275 // STRIKETHROUGH
5276 if ($textvar & TextVars::FD_LINETHROUGH) { // mPDF 5.7.1 // mPDF 6
5277
5278 // mPDF 5.7.3 inline text-decoration parameters
5279 $c = $this->textparam['s-decoration']['color'];
5280
5281 if ($this->FillColor != $c) {
5282 $sub .= ' ' . $c . ' ';
5283 }
5284
5285 // mPDF 5.7.3 inline text-decoration parameters
5286 $decorationfontkey = $this->textparam['s-decoration']['fontkey'];
5287 $decorationfontsize = $this->textparam['s-decoration']['fontsize'] / $shrin_k;
5288
5289 // Use yStrikeoutSize from OS/2 if available
5290 if (isset($this->fonts[$decorationfontkey]['strs']) && $this->fonts[$decorationfontkey]['strs']) {
5291 $ut = $this->fonts[$decorationfontkey]['strs'] / 1000 * $decorationfontsize;
5292 } // else use underlineThickness from post if available
5293 elseif (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
5294 $ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
5295 } else {
5296 $ut = 50 / 1000 * $decorationfontsize;
5297 }
5298
5299 // Use yStrikeoutPosition from OS/2 if available
5300 if (isset($this->fonts[$decorationfontkey]['strp']) && $this->fonts[$decorationfontkey]['strp']) {
5301 $up = $this->fonts[$decorationfontkey]['strp'];
5302 $adjusty = (-$up / 1000 * $decorationfontsize);
5303 } // else use a fraction ($this->baselineS) of CapHeight
5304 else {
5305 if (isset($this->fonts[$decorationfontkey]['desc']['CapHeight']) && $this->fonts[$decorationfontkey]['desc']['CapHeight']) {
5306 $ch = $this->fonts[$decorationfontkey]['desc']['CapHeight'];
5307 } else {
5308 $ch = 700;
5309 }
5310 $adjusty = (-$ch / 1000 * $decorationfontsize) * $this->baselineS;
5311 }
5312
5313 $sbaseline = $glyphYorigin - $this->textparam['s-decoration']['baseline'] / $shrin_k;
5314
5315 $olw = $this->LineWidth;
5316
5317 $sub .=' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * Mpdf::SCALE));
5318 $sub .=' ' . $this->_dounderline($this->x + $dx, $this->y + $sbaseline + $adjusty, $txt, $OTLdata, $textvar);
5319 $sub .=' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * Mpdf::SCALE));
5320
5321 if ($this->FillColor != $c) {
5322 $sub .= ' ' . $this->FillColor . ' ';
5323 }
5324 }
5325
5326 // mPDF 5.7.3 inline text-decoration parameters
5327 // OVERLINE
5328 if ($textvar & TextVars::FD_OVERLINE) { // mPDF 5.7.1 // mPDF 6
5329 // mPDF 5.7.3 inline text-decoration parameters
5330 $c = $this->textparam['o-decoration']['color'];
5331 if ($this->FillColor != $c) {
5332 $sub .= ' ' . $c . ' ';
5333 }
5334
5335 // mPDF 5.7.3 inline text-decoration parameters
5336 $decorationfontkey = (int) (((float) $this->textparam['o-decoration']['fontkey']) / $shrin_k);
5337 $decorationfontsize = $this->textparam['o-decoration']['fontsize'];
5338
5339 if (isset($this->fonts[$decorationfontkey]['ut']) && $this->fonts[$decorationfontkey]['ut']) {
5340 $ut = $this->fonts[$decorationfontkey]['ut'] / 1000 * $decorationfontsize;
5341 } else {
5342 $ut = 60 / 1000 * $decorationfontsize;
5343 }
5344 if (isset($this->fonts[$decorationfontkey]['desc']['CapHeight']) && $this->fonts[$decorationfontkey]['desc']['CapHeight']) {
5345 $ch = $this->fonts[$decorationfontkey]['desc']['CapHeight'];
5346 } else {
5347 $ch = 700;
5348 }
5349 $adjusty = (-$ch / 1000 * $decorationfontsize) * $this->baselineO;
5350 $obaseline = $glyphYorigin - $this->textparam['o-decoration']['baseline'] / $shrin_k;
5351 $olw = $this->LineWidth;
5352 $sub .=' ' . (sprintf(' %.3F w 0 j 0 J ', $ut * Mpdf::SCALE));
5353 $sub .=' ' . $this->_dounderline($this->x + $dx, $this->y + $obaseline + $adjusty, $txt, $OTLdata, $textvar);
5354 $sub .=' ' . (sprintf(' %.3F w 2 j 2 J ', $olw * Mpdf::SCALE));
5355 if ($this->FillColor != $c) {
5356 $sub .= ' ' . $this->FillColor . ' ';
5357 }
5358 }
5359
5360 // TEXT SHADOW
5361 if ($this->textshadow) { // First to process is last in CSS comma separated shadows
5362 foreach ($this->textshadow as $ts) {
5363 $s .= ' q ';
5364 $s .= $this->SetTColor($ts['col'], true) . "\n";
5365 if ($ts['col'][0] == 5 && ord($ts['col'][4]) < 100) { // RGBa
5366 $s .= $this->SetAlpha(ord($ts['col'][4]) / 100, 'Normal', true, 'F') . "\n";
5367 } elseif ($ts['col'][0] == 6 && ord($ts['col'][5]) < 100) { // CMYKa
5368 $s .= $this->SetAlpha(ord($ts['col'][5]) / 100, 'Normal', true, 'F') . "\n";
5369 } elseif ($ts['col'][0] == 1 && $ts['col'][2] == 1 && ord($ts['col'][3]) < 100) { // Gray
5370 $s .= $this->SetAlpha(ord($ts['col'][3]) / 100, 'Normal', true, 'F') . "\n";
5371 }
5372 $s .= sprintf(' 1 0 0 1 %.4F %.4F cm', $ts['x'] * Mpdf::SCALE, -$ts['y'] * Mpdf::SCALE) . "\n";
5373 $s .= $sub;
5374 $s .= ' Q ';
5375 }
5376 }
5377
5378 $s .= $sub;
5379
5380 // COLOR
5381 if ($this->ColorFlag) {
5382 $s .=' Q';
5383 }
5384
5385 // LINK
5386 if ($link != '') {
5387 $this->Link($this->x, $boxtop, $w, $boxheight, $link);
5388 }
5389 }
5390 if ($s) {
5391 $this->writer->write($s);
5392 }
5393
5394 // WORD SPACING
5395 if ($this->ws && !$this->usingCoreFont) {
5396 $this->writer->write(sprintf('BT %.3F Tc ET', $this->charspacing));
5397 }
5398 $this->lasth = $h;
5399 if (strpos($txt, "\n") !== false) {
5400 $ln = 1; // cell recognizes \n from <BR> tag
5401 }
5402 if ($ln > 0) {
5403 // Go to next line
5404 $this->y += $h;
5405 if ($ln == 1) {
5406 // Move to next line
5407 if ($currentx != 0) {
5408 $this->x = $currentx;
5409 } else {
5410 $this->x = $this->lMargin;
5411 }
5412 }
5413 } else {
5414 $this->x+=$w;
5415 }
5416 }
5417
5418 function applyGPOSpdf($txt, $aix, $x, $y, $OTLdata, $textvar = 0)
5419 {
5420 // Generate PDF string
5421 // ==============================
5422 if ((isset($this->CurrentFont['sip']) && $this->CurrentFont['sip']) || (isset($this->CurrentFont['smp']) && $this->CurrentFont['smp'])) {
5423 $sipset = true;
5424 } else {
5425 $sipset = false;
5426 }
5427
5428 if ($textvar & TextVars::FC_SMALLCAPS) {
5429 $smcaps = true;
5430 } // IF SmallCaps using transformation, NOT OTL
5431 else {
5432 $smcaps = false;
5433 }
5434
5435 if ($sipset) {
5436 $fontid = $last_fontid = $original_fontid = $this->CurrentFont['subsetfontids'][0];
5437 } else {
5438 $fontid = $last_fontid = $original_fontid = $this->CurrentFont['i'];
5439 }
5440 $SmallCapsON = false; // state: uppercase/not
5441 $lastSmallCapsON = false; // state: uppercase/not
5442 $last_fontsize = $fontsize = $this->FontSizePt;
5443 $last_fontstretch = $fontstretch = 100;
5444 $groupBreak = false;
5445
5446 $unicode = $this->UTF8StringToArray($txt);
5447
5448 $GPOSinfo = (isset($OTLdata['GPOSinfo']) ? $OTLdata['GPOSinfo'] : []);
5449 $charspacing = ($this->charspacing * 1000 / $this->FontSizePt);
5450 $wordspacing = ($this->ws * 1000 / $this->FontSizePt);
5451
5452 $XshiftBefore = 0;
5453 $XshiftAfter = 0;
5454 $lastYPlacement = 0;
5455
5456 if ($sipset) {
5457 // mPDF 6 DELETED ********
5458 // $txt= preg_replace('/'.preg_quote($this->aliasNbPg,'/').'/', chr(7), $txt); // ? Need to adjust OTL info
5459 // $txt= preg_replace('/'.preg_quote($this->aliasNbPgGp,'/').'/', chr(8), $txt); // ? Need to adjust OTL info
5460 $tj = '<';
5461 } else {
5462 $tj = '(';
5463 }
5464
5465 for ($i = 0; $i < count($unicode); $i++) {
5466 $c = $unicode[$i];
5467 $tx = '';
5468 $XshiftBefore = $XshiftAfter;
5469 $XshiftAfter = 0;
5470 $YPlacement = 0;
5471 $groupBreak = false;
5472 $kashida = 0;
5473 if (!empty($OTLdata)) {
5474 // YPlacement from GPOS
5475 if (isset($GPOSinfo[$i]['YPlacement']) && $GPOSinfo[$i]['YPlacement']) {
5476 $YPlacement = $GPOSinfo[$i]['YPlacement'] * $this->FontSizePt / $this->CurrentFont['unitsPerEm'];
5477 $groupBreak = true;
5478 }
5479 // XPlacement from GPOS
5480 if (isset($GPOSinfo[$i]['XPlacement']) && $GPOSinfo[$i]['XPlacement']) {
5481 if (!isset($GPOSinfo[$i]['wDir']) || $GPOSinfo[$i]['wDir'] != 'RTL') {
5482 if (isset($GPOSinfo[$i]['BaseWidth'])) {
5483 $GPOSinfo[$i]['XPlacement'] -= $GPOSinfo[$i]['BaseWidth'];
5484 }
5485 }
5486
5487 // Convert to PDF Text space (thousandths of a unit );
5488 $XshiftBefore += $GPOSinfo[$i]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
5489 $XshiftAfter += -$GPOSinfo[$i]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
5490 }
5491
5492 // Kashida from GPOS
5493 // Kashida is set as an absolute length value, but to adjust text needs to be converted to
5494 // font-related size
5495 if (isset($GPOSinfo[$i]['kashida_space']) && $GPOSinfo[$i]['kashida_space']) {
5496 $kashida = $GPOSinfo[$i]['kashida_space'];
5497 }
5498
5499 if ($c == 32) { // word spacing
5500 $XshiftAfter += $wordspacing;
5501 }
5502
5503 if (substr($OTLdata['group'], ($i + 1), 1) != 'M') { // Don't add inter-character spacing before Marks
5504 $XshiftAfter += $charspacing;
5505 }
5506
5507 // ...applyGPOSpdf...
5508 // XAdvance from GPOS - Convert to PDF Text space (thousandths of a unit );
5509 if (((isset($GPOSinfo[$i]['wDir']) && $GPOSinfo[$i]['wDir'] != 'RTL') || !isset($GPOSinfo[$i]['wDir'])) && isset($GPOSinfo[$i]['XAdvanceL']) && $GPOSinfo[$i]['XAdvanceL']) {
5510 $XshiftAfter += $GPOSinfo[$i]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
5511 } elseif (isset($GPOSinfo[$i]['wDir']) && $GPOSinfo[$i]['wDir'] == 'RTL' && isset($GPOSinfo[$i]['XAdvanceR']) && $GPOSinfo[$i]['XAdvanceR']) {
5512 $XshiftAfter += $GPOSinfo[$i]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
5513 }
5514 } // Character & Word spacing - if NOT OTL
5515 else {
5516 $XshiftAfter += $charspacing;
5517 if ($c == 32) {
5518 $XshiftAfter += $wordspacing;
5519 }
5520 }
5521
5522 // IF Kerning done using pairs rather than OTL
5523 if ($textvar & TextVars::FC_KERNING) {
5524 if ($i > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]])) {
5525 $XshiftBefore += $this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]];
5526 }
5527 }
5528
5529 if ($YPlacement != $lastYPlacement) {
5530 $groupBreak = true;
5531 }
5532
5533 if ($XshiftBefore) { // +ve value in PDF moves to the left
5534 // If Fontstretch is ongoing, need to adjust X adjustments because these will be stretched out.
5535 $XshiftBefore *= 100 / $last_fontstretch;
5536 if ($sipset) {
5537 $tj .= sprintf('>%d<', (-$XshiftBefore));
5538 } else {
5539 $tj .= sprintf(')%d(', (-$XshiftBefore));
5540 }
5541 }
5542
5543 // Small-Caps
5544 if ($smcaps) {
5545 if (isset($this->upperCase[$c])) {
5546 $c = $this->upperCase[$c];
5547 // $this->CurrentFont['subset'][$this->upperCase[$c]] = $this->upperCase[$c]; // add the CAP to subset
5548 $SmallCapsON = true;
5549 // For $sipset
5550 if (!$lastSmallCapsON) { // Turn ON SmallCaps
5551 $groupBreak = true;
5552 $fontstretch = $this->smCapsStretch;
5553 $fontsize = $this->FontSizePt * $this->smCapsScale;
5554 }
5555 } else {
5556 $SmallCapsON = false;
5557 if ($lastSmallCapsON) { // Turn OFF SmallCaps
5558 $groupBreak = true;
5559 $fontstretch = 100;
5560 $fontsize = $this->FontSizePt;
5561 }
5562 }
5563 }
5564
5565 // Prepare Text and Select Font ID
5566 if ($sipset) {
5567 // mPDF 6 DELETED ********
5568 // if ($c == 7 || $c == 8) {
5569 // if ($original_fontid != $last_fontid) {
5570 // $groupBreak = true;
5571 // $fontid = $original_fontid;
5572 // }
5573 // if ($c == 7) { $tj .= $this->aliasNbPgHex; }
5574 // else { $tj .= $this->aliasNbPgGpHex; }
5575 // continue;
5576 // }
5577 for ($j = 0; $j < 99; $j++) {
5578 $init = array_search($c, $this->CurrentFont['subsets'][$j]);
5579 if ($init !== false) {
5580 if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5581 $groupBreak = true;
5582 $fontid = $this->CurrentFont['subsetfontids'][$j];
5583 }
5584 $tx = sprintf("%02s", strtoupper(dechex($init)));
5585 break;
5586 } elseif (count($this->CurrentFont['subsets'][$j]) < 255) {
5587 $n = count($this->CurrentFont['subsets'][$j]);
5588 $this->CurrentFont['subsets'][$j][$n] = $c;
5589 if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5590 $groupBreak = true;
5591 $fontid = $this->CurrentFont['subsetfontids'][$j];
5592 }
5593 $tx = sprintf("%02s", strtoupper(dechex($n)));
5594 break;
5595 } elseif (!isset($this->CurrentFont['subsets'][($j + 1)])) {
5596 $this->CurrentFont['subsets'][($j + 1)] = [0 => 0];
5597 $this->CurrentFont['subsetfontids'][($j + 1)] = count($this->fonts) + $this->extraFontSubsets + 1;
5598 $this->extraFontSubsets++;
5599 }
5600 }
5601 } else {
5602 $tx = UtfString::code2utf($c);
5603 if ($this->usingCoreFont) {
5604 $tx = utf8_decode($tx);
5605 } else {
5606 $tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
5607 }
5608 $tx = $this->writer->escape($tx);
5609 }
5610
5611 // If any settings require a new Text Group
5612 if ($groupBreak || $fontstretch != $last_fontstretch) {
5613 if ($sipset) {
5614 $tj .= '>] TJ ';
5615 } else {
5616 $tj .= ')] TJ ';
5617 }
5618 if ($fontid != $last_fontid || $fontsize != $last_fontsize) {
5619 $tj .= sprintf(' /F%d %.3F Tf ', $fontid, $fontsize);
5620 }
5621 if ($fontstretch != $last_fontstretch) {
5622 $tj .= sprintf('%d Tz ', $fontstretch);
5623 }
5624 if ($YPlacement != $lastYPlacement) {
5625 $tj .= sprintf('%.3F Ts ', $YPlacement);
5626 }
5627 if ($sipset) {
5628 $tj .= '[<';
5629 } else {
5630 $tj .= '[(';
5631 }
5632 }
5633
5634 // Output the code for the txt character
5635 $tj .= $tx;
5636 $lastSmallCapsON = $SmallCapsON;
5637 $last_fontid = $fontid;
5638 $last_fontsize = $fontsize;
5639 $last_fontstretch = $fontstretch;
5640
5641 // Kashida
5642 if ($kashida) {
5643 $c = 0x0640; // add the Tatweel U+0640
5644 if (isset($this->CurrentFont['subset'])) {
5645 $this->CurrentFont['subset'][$c] = $c;
5646 }
5647 $kashida *= 1000 / $this->FontSizePt;
5648 $tatw = $this->_getCharWidth($this->CurrentFont['cw'], 0x0640);
5649
5650 // Get YPlacement from next Base character
5651 $nextbase = $i + 1;
5652 while ($OTLdata['group'][$nextbase] != 'C') {
5653 $nextbase++;
5654 }
5655 if (isset($GPOSinfo[$nextbase]) && isset($GPOSinfo[$nextbase]['YPlacement']) && $GPOSinfo[$nextbase]['YPlacement']) {
5656 $YPlacement = $GPOSinfo[$nextbase]['YPlacement'] * $this->FontSizePt / $this->CurrentFont['unitsPerEm'];
5657 }
5658
5659 // Prepare Text and Select Font ID
5660 if ($sipset) {
5661 for ($j = 0; $j < 99; $j++) {
5662 $init = array_search($c, $this->CurrentFont['subsets'][$j]);
5663 if ($init !== false) {
5664 if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5665 $fontid = $this->CurrentFont['subsetfontids'][$j];
5666 }
5667 $tx = sprintf("%02s", strtoupper(dechex($init)));
5668 break;
5669 } elseif (count($this->CurrentFont['subsets'][$j]) < 255) {
5670 $n = count($this->CurrentFont['subsets'][$j]);
5671 $this->CurrentFont['subsets'][$j][$n] = $c;
5672 if ($this->CurrentFont['subsetfontids'][$j] != $last_fontid) {
5673 $fontid = $this->CurrentFont['subsetfontids'][$j];
5674 }
5675 $tx = sprintf("%02s", strtoupper(dechex($n)));
5676 break;
5677 } elseif (!isset($this->CurrentFont['subsets'][($j + 1)])) {
5678 $this->CurrentFont['subsets'][($j + 1)] = [0 => 0];
5679 $this->CurrentFont['subsetfontids'][($j + 1)] = count($this->fonts) + $this->extraFontSubsets + 1;
5680 $this->extraFontSubsets++;
5681 }
5682 }
5683 } else {
5684 $tx = UtfString::code2utf($c);
5685 $tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
5686 $tx = $this->writer->escape($tx);
5687 }
5688
5689 if ($kashida > $tatw) {
5690 // Insert multiple tatweel characters, repositioning the last one to give correct total length
5691 $fontstretch = 100;
5692 $nt = intval($kashida / $tatw);
5693 $nudgeback = (($nt + 1) * $tatw) - $kashida;
5694 $optx = str_repeat($tx, $nt);
5695 if ($sipset) {
5696 $optx .= sprintf('>%d<', ($nudgeback));
5697 } else {
5698 $optx .= sprintf(')%d(', ($nudgeback));
5699 }
5700 $optx .= $tx; // #last
5701 } else {
5702 // Insert single tatweel character and use fontstretch to get correct length
5703 $fontstretch = ($kashida / $tatw) * 100;
5704 $optx = $tx;
5705 }
5706
5707 if ($sipset) {
5708 $tj .= '>] TJ ';
5709 } else {
5710 $tj .= ')] TJ ';
5711 }
5712 if ($fontid != $last_fontid || $fontsize != $last_fontsize) {
5713 $tj .= sprintf(' /F%d %.3F Tf ', $fontid, $fontsize);
5714 }
5715 if ($fontstretch != $last_fontstretch) {
5716 $tj .= sprintf('%d Tz ', $fontstretch);
5717 }
5718 $tj .= sprintf('%.3F Ts ', $YPlacement);
5719 if ($sipset) {
5720 $tj .= '[<';
5721 } else {
5722 $tj .= '[(';
5723 }
5724
5725 // Output the code for the txt character(s)
5726 $tj .= $optx;
5727 $last_fontid = $fontid;
5728 $last_fontstretch = $fontstretch;
5729 $fontstretch = 100;
5730 }
5731
5732 $lastYPlacement = $YPlacement;
5733 }
5734
5735
5736 // Finish up
5737 if ($sipset) {
5738 $tj .= '>';
5739 if ($XshiftAfter) {
5740 $tj .= sprintf('%d', (-$XshiftAfter));
5741 }
5742 if ($last_fontid != $original_fontid) {
5743 $tj .= '] TJ ';
5744 $tj .= sprintf(' /F%d %.3F Tf ', $original_fontid, $fontsize);
5745 $tj .= '[';
5746 }
5747 $tj = preg_replace('/([^\\\])<>/', '\\1 ', $tj);
5748 } else {
5749 $tj .= ')';
5750 if ($XshiftAfter) {
5751 $tj .= sprintf('%d', (-$XshiftAfter));
5752 }
5753 if ($last_fontid != $original_fontid) {
5754 $tj .= '] TJ ';
5755 $tj .= sprintf(' /F%d %.3F Tf ', $original_fontid, $fontsize);
5756 $tj .= '[';
5757 }
5758 $tj = preg_replace('/([^\\\])\‍(\‍)/', '\\1 ', $tj);
5759 }
5760
5761 $s = sprintf(' BT ' . $aix . ' 0 Tc 0 Tw [%s] TJ ET ', $x, $y, $tj);
5762
5763 // echo $s."\n\n"; // exit;
5764
5765 return $s;
5766 }
5767
5768 function _kern($txt, $mode, $aix, $x, $y)
5769 {
5770 if ($mode == 'MBTw') { // Multibyte requiring word spacing
5771 $space = ' ';
5772 // Convert string to UTF-16BE without BOM
5773 $space = $this->writer->utf8ToUtf16BigEndian($space, false);
5774 $space = $this->writer->escape($space);
5775 $s = sprintf(' BT ' . $aix, $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE);
5776 $t = explode(' ', $txt);
5777 for ($i = 0; $i < count($t); $i++) {
5778 $tx = $t[$i];
5779
5780 $tj = '(';
5781 $unicode = $this->UTF8StringToArray($tx);
5782 for ($ti = 0; $ti < count($unicode); $ti++) {
5783 if ($ti > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($ti - 1)]][$unicode[$ti]])) {
5784 $kern = -$this->CurrentFont['kerninfo'][$unicode[($ti - 1)]][$unicode[$ti]];
5785 $tj .= sprintf(')%d(', $kern);
5786 }
5787 $tc = UtfString::code2utf($unicode[$ti]);
5788 $tc = $this->writer->utf8ToUtf16BigEndian($tc, false);
5789 $tj .= $this->writer->escape($tc);
5790 }
5791 $tj .= ')';
5792 $s .= sprintf(' %.3F Tc [%s] TJ', $this->charspacing, $tj);
5793
5794
5795 if (($i + 1) < count($t)) {
5796 $s .= sprintf(' %.3F Tc (%s) Tj', $this->ws + $this->charspacing, $space);
5797 }
5798 }
5799 $s .= ' ET ';
5800 } elseif (!$this->usingCoreFont) {
5801 $s = '';
5802 $tj = '(';
5803 $unicode = $this->UTF8StringToArray($txt);
5804 for ($i = 0; $i < count($unicode); $i++) {
5805 if ($i > 0 && isset($this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]])) {
5806 $kern = -$this->CurrentFont['kerninfo'][$unicode[($i - 1)]][$unicode[$i]];
5807 $tj .= sprintf(')%d(', $kern);
5808 }
5809 $tx = UtfString::code2utf($unicode[$i]);
5810 $tx = $this->writer->utf8ToUtf16BigEndian($tx, false);
5811 $tj .= $this->writer->escape($tx);
5812 }
5813 $tj .= ')';
5814 $s .= sprintf(' BT ' . $aix . ' [%s] TJ ET ', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $tj);
5815 } else { // CORE Font
5816 $s = '';
5817 $tj = '(';
5818 $l = strlen($txt);
5819 for ($i = 0; $i < $l; $i++) {
5820 if ($i > 0 && isset($this->CurrentFont['kerninfo'][$txt[($i - 1)]][$txt[$i]])) {
5821 $kern = -$this->CurrentFont['kerninfo'][$txt[($i - 1)]][$txt[$i]];
5822 $tj .= sprintf(')%d(', $kern);
5823 }
5824 $tj .= $this->writer->escape($txt[$i]);
5825 }
5826 $tj .= ')';
5827 $s .= sprintf(' BT ' . $aix . ' [%s] TJ ET ', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $tj);
5828 }
5829
5830 return $s;
5831 }
5832
5833 function MultiCell(
5834 $w,
5835 $h,
5836 $txt,
5837 $border = 0,
5838 $align = '',
5839 $fill = 0,
5840 $link = '',
5841 $directionality = 'ltr',
5842 $encoded = false,
5843 $OTLdata = false,
5844 $maxrows = false
5845 ) {
5846 // maxrows is called from mpdfform->TEXTAREA
5847 // Parameter (pre-)encoded - When called internally from form::textarea -
5848 // mb_encoding already done and OTL - but not reverse RTL
5849 if (!$encoded) {
5850
5851 $txt = $this->purify_utf8_text($txt);
5852
5853 if ($this->text_input_as_HTML) {
5854 $txt = $this->all_entities_to_utf8($txt);
5855 }
5856
5857 if ($this->usingCoreFont) {
5858 $txt = mb_convert_encoding($txt, $this->mb_enc, 'UTF-8');
5859 }
5860
5861 if (preg_match("/([" . $this->pregRTLchars . "])/u", $txt)) {
5862 $this->biDirectional = true;
5863 }
5864
5865 /* -- OTL -- */
5866 if (!is_array($OTLdata)) {
5867 unset($OTLdata);
5868 }
5869
5870 // Use OTL OpenType Table Layout - GSUB & GPOS
5871 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
5872 $txt = $this->otl->applyOTL($txt, $this->CurrentFont['useOTL']);
5873 $OTLdata = $this->otl->OTLdata;
5874 }
5875
5876 if ($directionality == 'rtl' || $this->biDirectional) {
5877 if (!isset($OTLdata)) {
5878 $unicode = $this->UTF8StringToArray($txt, false);
5879 $is_strong = false;
5880 $this->getBasicOTLdata($OTLdata, $unicode, $is_strong);
5881 }
5882 }
5883 /* -- END OTL -- */
5884 }
5885
5886 if (!$align) {
5887 $align = $this->defaultAlign;
5888 }
5889
5890 // Output text with automatic or explicit line breaks
5891 $cw = &$this->CurrentFont['cw'];
5892
5893 if ($w == 0) {
5894 $w = $this->w - $this->rMargin - $this->x;
5895 }
5896
5897 $wmax = ($w - ($this->cMarginL + $this->cMarginR));
5898
5899 if ($this->usingCoreFont) {
5900 $s = str_replace("\r", '', $txt);
5901 $nb = strlen($s);
5902 while ($nb > 0 and $s[$nb - 1] == "\n") {
5903 $nb--;
5904 }
5905 } else {
5906 $s = str_replace("\r", '', $txt);
5907 $nb = mb_strlen($s, $this->mb_enc);
5908 while ($nb > 0 and mb_substr($s, $nb - 1, 1, $this->mb_enc) == "\n") {
5909 $nb--;
5910 }
5911 }
5912
5913 $b = 0;
5914
5915 if ($border) {
5916
5917 if ($border == 1) {
5918 $border = 'LTRB';
5919 $b = 'LRT';
5920 $b2 = 'LR';
5921 } else {
5922 $b2 = '';
5923 if (is_int(strpos($border, 'L'))) {
5924 $b2 .= 'L';
5925 }
5926 if (is_int(strpos($border, 'R'))) {
5927 $b2 .= 'R';
5928 }
5929 $b = is_int(strpos($border, 'T')) ? $b2 . 'T' : $b2;
5930 }
5931 }
5932
5933 $sep = -1;
5934 $i = 0;
5935 $j = 0;
5936 $l = 0;
5937 $ns = 0;
5938 $nl = 1;
5939
5940 $rows = 0;
5941 $start_y = $this->y;
5942
5943 if (!$this->usingCoreFont) {
5944
5945 $inclCursive = false;
5946
5947 if (preg_match("/([" . $this->pregCURSchars . "])/u", $s)) {
5948 $inclCursive = true;
5949 }
5950
5951 while ($i < $nb) {
5952
5953 // Get next character
5954 $c = mb_substr($s, $i, 1, $this->mb_enc);
5955
5956 if ($c === "\n") { // Explicit line break
5957
5958 // WORD SPACING
5959 $this->ResetSpacing();
5960 $tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
5961 $tmpOTLdata = false;
5962
5963 /* -- OTL -- */
5964 if (isset($OTLdata)) {
5965 $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
5966 $this->otl->trimOTLdata($tmpOTLdata, false, true);
5967 $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
5968 }
5969 /* -- END OTL -- */
5970
5971 $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
5972
5973 if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
5974 return false;
5975 }
5976
5977 $i++;
5978 $sep = -1;
5979 $j = $i;
5980 $l = 0;
5981 $ns = 0;
5982 $nl++;
5983
5984 if ($border and $nl == 2) {
5985 $b = $b2;
5986 }
5987
5988 continue;
5989 }
5990
5991 if ($c == " ") {
5992 $sep = $i;
5993 $ls = $l;
5994 $ns++;
5995 }
5996
5997 $l += $this->GetCharWidthNonCore($c);
5998
5999 if ($l > $wmax) {
6000
6001 // Automatic line break
6002 if ($sep == -1) { // Only one word
6003
6004 if ($i == $j) {
6005 $i++;
6006 }
6007
6008 // WORD SPACING
6009 $this->ResetSpacing();
6010 $tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
6011 $tmpOTLdata = false;
6012
6013 /* -- OTL -- */
6014 if (isset($OTLdata)) {
6015 $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
6016 $this->otl->trimOTLdata($tmpOTLdata, false, true);
6017 $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
6018 }
6019 /* -- END OTL -- */
6020
6021 $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
6022
6023 } else {
6024
6025 $tmp = rtrim(mb_substr($s, $j, $sep - $j, $this->mb_enc));
6026 $tmpOTLdata = false;
6027
6028 /* -- OTL -- */
6029 if (isset($OTLdata)) {
6030 $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $sep - $j);
6031 $this->otl->trimOTLdata($tmpOTLdata, false, true);
6032 }
6033 /* -- END OTL -- */
6034
6035 if ($align === 'J') {
6036
6037 // JUSTIFY J using Unicode fonts (Word spacing doesn't work)
6038 // WORD SPACING UNICODE
6039 // Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
6040
6041 $tmp = str_replace(chr(194) . chr(160), chr(32), $tmp);
6042 $len_ligne = $this->GetStringWidth($tmp, false, $tmpOTLdata);
6043 $nb_carac = mb_strlen($tmp, $this->mb_enc);
6044 $nb_spaces = mb_substr_count($tmp, ' ', $this->mb_enc);
6045
6046 // Take off number of Marks
6047 // Use GPOS OTL
6048
6049 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'])) {
6050 if (isset($tmpOTLdata['group']) && $tmpOTLdata['group']) {
6051 $nb_carac -= substr_count($tmpOTLdata['group'], 'M');
6052 }
6053 }
6054
6055 list($charspacing, $ws, $kashida) = $this->GetJspacing($nb_carac, $nb_spaces, ((($wmax) - $len_ligne) * Mpdf::SCALE), $inclCursive, $tmpOTLdata);
6056 $this->SetSpacing($charspacing, $ws);
6057 }
6058
6059 if (isset($OTLdata)) {
6060 $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
6061 }
6062
6063 $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
6064
6065 $i = $sep + 1;
6066 }
6067
6068 if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
6069 return false;
6070 }
6071
6072 $sep = -1;
6073 $j = $i;
6074 $l = 0;
6075 $ns = 0;
6076 $nl++;
6077
6078 if ($border and $nl == 2) {
6079 $b = $b2;
6080 }
6081
6082 } else {
6083 $i++;
6084 }
6085 }
6086
6087 // Last chunk
6088 // WORD SPACING
6089
6090 $this->ResetSpacing();
6091
6092 } else {
6093
6094 while ($i < $nb) {
6095
6096 // Get next character
6097 $c = $s[$i];
6098 if ($c === "\n") {
6099
6100 // Explicit line break
6101 // WORD SPACING
6102
6103 $this->ResetSpacing();
6104 $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);
6105
6106 if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
6107 return false;
6108 }
6109
6110 $i++;
6111 $sep = -1;
6112 $j = $i;
6113 $l = 0;
6114 $ns = 0;
6115 $nl++;
6116
6117 if ($border and $nl == 2) {
6118 $b = $b2;
6119 }
6120
6121 continue;
6122 }
6123
6124 if ($c === ' ') {
6125 $sep = $i;
6126 $ls = $l;
6127 $ns++;
6128 }
6129
6130 $l += $this->GetCharWidthCore($c);
6131
6132 if ($l > $wmax) {
6133
6134 // Automatic line break
6135 if ($sep == -1) {
6136
6137 if ($i == $j) {
6138 $i++;
6139 }
6140
6141 // WORD SPACING
6142 $this->ResetSpacing();
6143 $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);
6144
6145 } else {
6146
6147 if ($align === 'J') {
6148
6149 $tmp = rtrim(substr($s, $j, $sep - $j));
6150
6151 // JUSTIFY J using Unicode fonts (Word spacing doesn't work)
6152 // WORD SPACING NON_UNICODE/CJK
6153 // Change NON_BREAKING SPACE to spaces so they are 'spaced' properly
6154
6155 $tmp = str_replace(chr(160), chr(32), $tmp);
6156 $len_ligne = $this->GetStringWidth($tmp);
6157 $nb_carac = strlen($tmp);
6158 $nb_spaces = substr_count($tmp, ' ');
6159 $tmpOTLdata = [];
6160
6161 list($charspacing, $ws, $kashida) = $this->GetJspacing($nb_carac, $nb_spaces, ((($wmax) - $len_ligne) * Mpdf::SCALE), false, $tmpOTLdata);
6162 $this->SetSpacing($charspacing, $ws);
6163 }
6164
6165 $this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill, $link);
6166 $i = $sep + 1;
6167 }
6168
6169 if ($maxrows != false && isset($this->form) && ($this->y - $start_y) / $h > $maxrows) {
6170 return false;
6171 }
6172
6173 $sep = -1;
6174 $j = $i;
6175 $l = 0;
6176 $ns = 0;
6177 $nl++;
6178
6179 if ($border and $nl == 2) {
6180 $b = $b2;
6181 }
6182
6183 } else {
6184 $i++;
6185 }
6186 }
6187
6188 // Last chunk
6189 // WORD SPACING
6190
6191 $this->ResetSpacing();
6192 }
6193
6194 // Last chunk
6195 if ($border and is_int(strpos($border, 'B'))) {
6196 $b .= 'B';
6197 }
6198
6199 if (!$this->usingCoreFont) {
6200
6201 $tmp = rtrim(mb_substr($s, $j, $i - $j, $this->mb_enc));
6202 $tmpOTLdata = false;
6203
6204 /* -- OTL -- */
6205 if (isset($OTLdata)) {
6206 $tmpOTLdata = $this->otl->sliceOTLdata($OTLdata, $j, $i - $j);
6207 $this->otl->trimOTLdata($tmpOTLdata, false, true);
6208 $this->magic_reverse_dir($tmp, $directionality, $tmpOTLdata);
6209 }
6210 /* -- END OTL -- */
6211
6212 $this->Cell($w, $h, $tmp, $b, 2, $align, $fill, $link, 0, 0, 0, 'M', 0, false, $tmpOTLdata);
6213 } else {
6214 $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill, $link);
6215 }
6216
6217 $this->x = $this->lMargin;
6218 }
6219
6220 /* -- DIRECTW -- */
6221
6222 function Write($h, $txt, $currentx = 0, $link = '', $directionality = 'ltr', $align = '', $fill = 0)
6223 {
6224 if (empty($this->directWrite)) {
6225 $this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
6226 }
6227
6228 $this->directWrite->Write($h, $txt, $currentx, $link, $directionality, $align, $fill);
6229 }
6230
6231 /* -- END DIRECTW -- */
6232
6233
6234 /* -- HTML-CSS -- */
6235
6237 {
6238 $saved = [];
6239 $saved['family'] = $this->FontFamily;
6240 $saved['style'] = $this->FontStyle;
6241 $saved['sizePt'] = $this->FontSizePt;
6242 $saved['size'] = $this->FontSize;
6243 $saved['HREF'] = $this->HREF;
6244 $saved['textvar'] = $this->textvar; // mPDF 5.7.1
6245 $saved['OTLtags'] = $this->OTLtags; // mPDF 5.7.1
6246 $saved['textshadow'] = $this->textshadow;
6247 $saved['linewidth'] = $this->LineWidth;
6248 $saved['drawcolor'] = $this->DrawColor;
6249 $saved['textparam'] = $this->textparam;
6250 $saved['lSpacingCSS'] = $this->lSpacingCSS;
6251 $saved['wSpacingCSS'] = $this->wSpacingCSS;
6252 $saved['I'] = $this->I;
6253 $saved['B'] = $this->B;
6254 $saved['colorarray'] = $this->colorarray;
6255 $saved['bgcolorarray'] = $this->spanbgcolorarray;
6256 $saved['border'] = $this->spanborddet;
6257 $saved['color'] = $this->TextColor;
6258 $saved['bgcolor'] = $this->FillColor;
6259 $saved['lang'] = $this->currentLang;
6260 $saved['fontLanguageOverride'] = $this->fontLanguageOverride; // mPDF 5.7.1
6261 $saved['display_off'] = $this->inlineDisplayOff;
6262
6263 return $saved;
6264 }
6265
6266 function restoreInlineProperties(&$saved)
6267 {
6268 $FontFamily = $saved['family'];
6269 $this->FontStyle = $saved['style'];
6270 $this->FontSizePt = $saved['sizePt'];
6271 $this->FontSize = $saved['size'];
6272
6273 $this->currentLang = $saved['lang'];
6274 $this->fontLanguageOverride = $saved['fontLanguageOverride']; // mPDF 5.7.1
6275
6276 $this->ColorFlag = ($this->FillColor != $this->TextColor); // Restore ColorFlag as well
6277
6278 $this->HREF = $saved['HREF'];
6279 $this->textvar = $saved['textvar']; // mPDF 5.7.1
6280 $this->OTLtags = $saved['OTLtags']; // mPDF 5.7.1
6281 $this->textshadow = $saved['textshadow'];
6282 $this->LineWidth = $saved['linewidth'];
6283 $this->DrawColor = $saved['drawcolor'];
6284 $this->textparam = $saved['textparam'];
6285 $this->inlineDisplayOff = $saved['display_off'];
6286
6287 $this->lSpacingCSS = $saved['lSpacingCSS'];
6288 if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
6289 $this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize);
6290 } else {
6291 $this->fixedlSpacing = false;
6292 }
6293 $this->wSpacingCSS = $saved['wSpacingCSS'];
6294 if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
6295 $this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize);
6296 } else {
6297 $this->minwSpacing = 0;
6298 }
6299
6300 $this->SetFont($FontFamily, $saved['style'], $saved['sizePt'], false);
6301
6302 $this->currentfontstyle = $saved['style'];
6303 $this->currentfontsize = $saved['sizePt'];
6304 $this->SetStylesArray(['B' => $saved['B'], 'I' => $saved['I']]); // mPDF 5.7.1
6305
6306 $this->TextColor = $saved['color'];
6307 $this->FillColor = $saved['bgcolor'];
6308 $this->colorarray = $saved['colorarray'];
6309 $cor = $saved['colorarray'];
6310 if ($cor) {
6311 $this->SetTColor($cor);
6312 }
6313 $this->spanbgcolorarray = $saved['bgcolorarray'];
6314 $cor = $saved['bgcolorarray'];
6315 if ($cor) {
6316 $this->SetFColor($cor);
6317 }
6318 $this->spanborddet = $saved['border'];
6319 }
6320
6321 // Used when ColActive for tables - updated to return first block with background fill OR borders
6323 {
6324 // Returns the first blocklevel that uses a bgcolor fill
6325 $startfill = 0;
6326 for ($i = 1; $i <= $this->blklvl; $i++) {
6327 if ($this->blk[$i]['bgcolor'] || $this->blk[$i]['border_left']['w'] || $this->blk[$i]['border_right']['w'] || $this->blk[$i]['border_top']['w'] || $this->blk[$i]['border_bottom']['w']) {
6328 $startfill = $i;
6329 break;
6330 }
6331 }
6332 return $startfill;
6333 }
6334
6335 // -------------------------FLOWING BLOCK------------------------------------//
6336 // The following functions were originally written by Damon Kohler //
6337 // --------------------------------------------------------------------------//
6338
6339 function saveFont()
6340 {
6341 $saved = [];
6342 $saved['family'] = $this->FontFamily;
6343 $saved['style'] = $this->FontStyle;
6344 $saved['sizePt'] = $this->FontSizePt;
6345 $saved['size'] = $this->FontSize;
6346 $saved['curr'] = &$this->CurrentFont;
6347 $saved['lang'] = $this->currentLang; // mPDF 6
6348 $saved['color'] = $this->TextColor;
6349 $saved['spanbgcolor'] = $this->spanbgcolor;
6350 $saved['spanbgcolorarray'] = $this->spanbgcolorarray;
6351 $saved['bord'] = $this->spanborder;
6352 $saved['border'] = $this->spanborddet;
6353 $saved['HREF'] = $this->HREF;
6354 $saved['textvar'] = $this->textvar; // mPDF 5.7.1
6355 $saved['textshadow'] = $this->textshadow;
6356 $saved['linewidth'] = $this->LineWidth;
6357 $saved['drawcolor'] = $this->DrawColor;
6358 $saved['textparam'] = $this->textparam;
6359 $saved['ReqFontStyle'] = $this->ReqFontStyle;
6360 $saved['fixedlSpacing'] = $this->fixedlSpacing;
6361 $saved['minwSpacing'] = $this->minwSpacing;
6362 return $saved;
6363 }
6364
6365 function restoreFont(&$saved, $write = true)
6366 {
6367 if (!isset($saved) || empty($saved)) {
6368 return;
6369 }
6370
6371 $this->FontFamily = $saved['family'];
6372 $this->FontStyle = $saved['style'];
6373 $this->FontSizePt = $saved['sizePt'];
6374 $this->FontSize = $saved['size'];
6375 $this->CurrentFont = &$saved['curr'];
6376 $this->currentLang = $saved['lang']; // mPDF 6
6377 $this->TextColor = $saved['color'];
6378 $this->spanbgcolor = $saved['spanbgcolor'];
6379 $this->spanbgcolorarray = $saved['spanbgcolorarray'];
6380 $this->spanborder = $saved['bord'];
6381 $this->spanborddet = $saved['border'];
6382 $this->ColorFlag = ($this->FillColor != $this->TextColor); // Restore ColorFlag as well
6383 $this->HREF = $saved['HREF'];
6384 $this->fixedlSpacing = $saved['fixedlSpacing'];
6385 $this->minwSpacing = $saved['minwSpacing'];
6386 $this->textvar = $saved['textvar']; // mPDF 5.7.1
6387 $this->textshadow = $saved['textshadow'];
6388 $this->LineWidth = $saved['linewidth'];
6389 $this->DrawColor = $saved['drawcolor'];
6390 $this->textparam = $saved['textparam'];
6391 if ($write) {
6392 $this->SetFont($saved['family'], $saved['style'], $saved['sizePt'], true, true); // force output
6393 $fontout = (sprintf('BT /F%d %.3F Tf ET', $this->CurrentFont['i'], $this->FontSizePt));
6394 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Font']) && $this->pageoutput[$this->page]['Font'] != $fontout) || !isset($this->pageoutput[$this->page]['Font']))) {
6395 $this->writer->write($fontout);
6396 }
6397 $this->pageoutput[$this->page]['Font'] = $fontout;
6398 } else {
6399 $this->SetFont($saved['family'], $saved['style'], $saved['sizePt'], false);
6400 }
6401 $this->ReqFontStyle = $saved['ReqFontStyle'];
6402 }
6403
6404 function newFlowingBlock($w, $h, $a = '', $is_table = false, $blockstate = 0, $newblock = true, $blockdir = 'ltr', $table_draft = false)
6405 {
6406 if (!$a) {
6407 if ($blockdir == 'rtl') {
6408 $a = 'R';
6409 } else {
6410 $a = 'L';
6411 }
6412 }
6413 $this->flowingBlockAttr['width'] = ($w * Mpdf::SCALE);
6414 // line height in user units
6415 $this->flowingBlockAttr['is_table'] = $is_table;
6416 $this->flowingBlockAttr['table_draft'] = $table_draft;
6417 $this->flowingBlockAttr['height'] = $h;
6418 $this->flowingBlockAttr['lineCount'] = 0;
6419 $this->flowingBlockAttr['align'] = $a;
6420 $this->flowingBlockAttr['font'] = [];
6421 $this->flowingBlockAttr['content'] = [];
6422 $this->flowingBlockAttr['contentB'] = [];
6423 $this->flowingBlockAttr['contentWidth'] = 0;
6424 $this->flowingBlockAttr['blockstate'] = $blockstate;
6425
6426 $this->flowingBlockAttr['newblock'] = $newblock;
6427 $this->flowingBlockAttr['valign'] = 'M';
6428 $this->flowingBlockAttr['blockdir'] = $blockdir;
6429 $this->flowingBlockAttr['cOTLdata'] = []; // mPDF 5.7.1
6430 $this->flowingBlockAttr['lastBidiText'] = ''; // mPDF 5.7.1
6431 if (!empty($this->otl)) {
6432 $this->otl->lastBidiStrongType = '';
6433 } // *OTL*
6434 }
6435
6436 function finishFlowingBlock($endofblock = false, $next = '')
6437 {
6438 $currentx = $this->x;
6439 // prints out the last chunk
6440 $is_table = $this->flowingBlockAttr['is_table'];
6441 $table_draft = $this->flowingBlockAttr['table_draft'];
6442 $maxWidth = & $this->flowingBlockAttr['width'];
6443 $stackHeight = & $this->flowingBlockAttr['height'];
6444 $align = & $this->flowingBlockAttr['align'];
6445 $content = & $this->flowingBlockAttr['content'];
6446 $contentB = & $this->flowingBlockAttr['contentB'];
6447 $font = & $this->flowingBlockAttr['font'];
6448 $contentWidth = & $this->flowingBlockAttr['contentWidth'];
6449 $lineCount = & $this->flowingBlockAttr['lineCount'];
6450 $valign = & $this->flowingBlockAttr['valign'];
6451 $blockstate = $this->flowingBlockAttr['blockstate'];
6452
6453 $cOTLdata = & $this->flowingBlockAttr['cOTLdata']; // mPDF 5.7.1
6454 $newblock = $this->flowingBlockAttr['newblock'];
6455 $blockdir = $this->flowingBlockAttr['blockdir'];
6456
6457 // *********** BLOCK BACKGROUND COLOR *****************//
6458 if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) {
6459 $fill = 0;
6460 } else {
6461 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
6462 $fill = 0;
6463 }
6464
6465 $hanger = '';
6466 // Always right trim!
6467 // Right trim last content and adjust width if needed to justify (later)
6468 if (isset($content[count($content) - 1]) && preg_match('/[ ]+$/', $content[count($content) - 1], $m)) {
6469 $strip = strlen($m[0]);
6470 $content[count($content) - 1] = substr($content[count($content) - 1], 0, (strlen($content[count($content) - 1]) - $strip));
6471 /* -- OTL -- */
6472 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6473 $this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], false, true);
6474 }
6475 /* -- END OTL -- */
6476 }
6477
6478 // the amount of space taken up so far in user units
6479 $usedWidth = 0;
6480
6481 // COLS
6482 $oldcolumn = $this->CurrCol;
6483
6484 if ($this->ColActive && !$is_table) {
6485 $this->breakpoints[$this->CurrCol][] = $this->y;
6486 } // *COLUMNS*
6487 // Print out each chunk
6488
6489 /* -- TABLES -- */
6490 if ($is_table) {
6491 $ipaddingL = 0;
6492 $ipaddingR = 0;
6493 $paddingL = 0;
6494 $paddingR = 0;
6495 } else {
6496 /* -- END TABLES -- */
6497 $ipaddingL = $this->blk[$this->blklvl]['padding_left'];
6498 $ipaddingR = $this->blk[$this->blklvl]['padding_right'];
6499 $paddingL = ($ipaddingL * Mpdf::SCALE);
6500 $paddingR = ($ipaddingR * Mpdf::SCALE);
6501 $this->cMarginL = $this->blk[$this->blklvl]['border_left']['w'];
6502 $this->cMarginR = $this->blk[$this->blklvl]['border_right']['w'];
6503
6504 // Added mPDF 3.0 Float DIV
6505 $fpaddingR = 0;
6506 $fpaddingL = 0;
6507 /* -- CSS-FLOAT -- */
6508 if (count($this->floatDivs)) {
6509 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
6510 if ($r_exists) {
6511 $fpaddingR = $r_width;
6512 }
6513 if ($l_exists) {
6514 $fpaddingL = $l_width;
6515 }
6516 }
6517 /* -- END CSS-FLOAT -- */
6518
6519 $usey = $this->y + 0.002;
6520 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
6521 $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
6522 }
6523 /* -- CSS-IMAGE-FLOAT -- */
6524 // If float exists at this level
6525 if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
6526 $fpaddingR += $this->floatmargins['R']['w'];
6527 }
6528 if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
6529 $fpaddingL += $this->floatmargins['L']['w'];
6530 }
6531 /* -- END CSS-IMAGE-FLOAT -- */
6532 } // *TABLES*
6533
6534
6535 $lineBox = [];
6536
6537 $this->_setInlineBlockHeights($lineBox, $stackHeight, $content, $font, $is_table);
6538
6539 if ($is_table && count($content) == 0) {
6540 $stackHeight = 0;
6541 }
6542
6543 if ($table_draft) {
6544 $this->y += $stackHeight;
6545 $this->objectbuffer = [];
6546 return 0;
6547 }
6548
6549 // While we're at it, check if contains cursive text
6550 // Change NBSP to SPACE.
6551 // Re-calculate contentWidth
6552 $contentWidth = 0;
6553
6554 foreach ($content as $k => $chunk) {
6555 $this->restoreFont($font[$k], false);
6556 if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
6557 // Soft Hyphens chr(173)
6558 if (!$this->usingCoreFont) {
6559 /* -- OTL -- */
6560 // mPDF 5.7.1
6561 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6562 $this->otl->removeChar($chunk, $cOTLdata[$k], "\xc2\xad");
6563 $this->otl->replaceSpace($chunk, $cOTLdata[$k]);
6564 $content[$k] = $chunk;
6565 } /* -- END OTL -- */ else { // *OTL*
6566 $content[$k] = $chunk = str_replace("\xc2\xad", '', $chunk);
6567 $content[$k] = $chunk = str_replace(chr(194) . chr(160), chr(32), $chunk);
6568 } // *OTL*
6569 } elseif ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
6570 $content[$k] = $chunk = str_replace(chr(173), '', $chunk);
6571 $content[$k] = $chunk = str_replace(chr(160), chr(32), $chunk);
6572 }
6573 $contentWidth += $this->GetStringWidth($chunk, true, (isset($cOTLdata[$k]) ? $cOTLdata[$k] : false), $this->textvar) * Mpdf::SCALE;
6574 } elseif (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
6575 // LIST MARKERS // mPDF 6 Lists
6576 if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
6577 // do nothing
6578 } else {
6579 $contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * Mpdf::SCALE;
6580 }
6581 }
6582 }
6583
6584 if (isset($font[count($font) - 1])) {
6585 $lastfontreqstyle = (isset($font[count($font) - 1]['ReqFontStyle']) ? $font[count($font) - 1]['ReqFontStyle'] : '');
6586 $lastfontstyle = (isset($font[count($font) - 1]['style']) ? $font[count($font) - 1]['style'] : '');
6587 } else {
6588 $lastfontreqstyle = null;
6589 $lastfontstyle = null;
6590 }
6591 if ($blockdir == 'ltr' && $lastfontreqstyle && strpos($lastfontreqstyle, "I") !== false && strpos($lastfontstyle, "I") === false) { // Artificial italic
6592 $lastitalic = $this->FontSize * 0.15 * Mpdf::SCALE;
6593 } else {
6594 $lastitalic = 0;
6595 }
6596
6597 // Get PAGEBREAK TO TEST for height including the bottom border/padding
6598 $check_h = max($this->divheight, $stackHeight);
6599
6600 // This fixes a proven bug...
6601 if ($endofblock && $newblock && $blockstate == 0 && !$content) {
6602 $check_h = 0;
6603 }
6604 // but ? needs to fix potentially more widespread...
6605 // if (!$content) { $check_h = 0; }
6606
6607 if ($this->blklvl > 0 && !$is_table) {
6608 if ($endofblock && $blockstate > 1) {
6609 if ($this->blk[$this->blklvl]['page_break_after_avoid']) {
6610 $check_h += $stackHeight;
6611 }
6612 $check_h += ($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']);
6613 }
6614 if (($newblock && ($blockstate == 1 || $blockstate == 3) && $lineCount == 0) || ($endofblock && $blockstate == 3 && $lineCount == 0)) {
6615 $check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']);
6616 }
6617 }
6618
6619 // Force PAGE break if column height cannot take check-height
6620 if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) {
6621 $this->SetCol($this->NbCol - 1);
6622 }
6623
6624 // Avoid just border/background-color moved on to next page
6625 if ($endofblock && $blockstate > 1 && !$content) {
6626 $buff = $this->margBuffer;
6627 } else {
6628 $buff = 0;
6629 }
6630
6631
6632 // PAGEBREAK
6633 if (!$is_table && ($this->y + $check_h) > ($this->PageBreakTrigger + $buff) and ! $this->InFooter and $this->AcceptPageBreak()) {
6634 $bak_x = $this->x; // Current X position
6635 // WORD SPACING
6636 $ws = $this->ws; // Word Spacing
6637 $charspacing = $this->charspacing; // Character Spacing
6638 $this->ResetSpacing();
6639
6640 $this->AddPage($this->CurOrientation);
6641
6642 $this->x = $bak_x;
6643 // Added to correct for OddEven Margins
6644 $currentx += $this->MarginCorrection;
6645 $this->x += $this->MarginCorrection;
6646
6647 // WORD SPACING
6648 $this->SetSpacing($charspacing, $ws);
6649 }
6650
6651
6652 /* -- COLUMNS -- */
6653 // COLS
6654 // COLUMN CHANGE
6655 if ($this->CurrCol != $oldcolumn) {
6656 $currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
6657 $this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
6658 $oldcolumn = $this->CurrCol;
6659 }
6660
6661
6662 if ($this->ColActive && !$is_table) {
6663 $this->breakpoints[$this->CurrCol][] = $this->y;
6664 }
6665 /* -- END COLUMNS -- */
6666
6667 // TOP MARGIN
6668 if ($newblock && ($blockstate == 1 || $blockstate == 3) && ($this->blk[$this->blklvl]['margin_top']) && $lineCount == 0 && !$is_table) {
6669 $this->DivLn($this->blk[$this->blklvl]['margin_top'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
6670 if ($this->ColActive) {
6671 $this->breakpoints[$this->CurrCol][] = $this->y;
6672 } // *COLUMNS*
6673 }
6674
6675 if ($newblock && ($blockstate == 1 || $blockstate == 3) && $lineCount == 0 && !$is_table) {
6676 $this->blk[$this->blklvl]['y0'] = $this->y;
6677 $this->blk[$this->blklvl]['startpage'] = $this->page;
6678 if ($this->blk[$this->blklvl]['float']) {
6679 $this->blk[$this->blklvl]['float_start_y'] = $this->y;
6680 }
6681 if ($this->ColActive) {
6682 $this->breakpoints[$this->CurrCol][] = $this->y;
6683 } // *COLUMNS*
6684 }
6685
6686 // Paragraph INDENT
6687 $WidthCorrection = 0;
6688 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
6689 $ti = $this->sizeConverter->convert($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4
6690 $WidthCorrection = ($ti * Mpdf::SCALE);
6691 }
6692
6693
6694 // PADDING and BORDER spacing/fill
6695 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 0) && (!$is_table)) {
6696 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
6697 $this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'], -3, true, false, 1);
6698 if ($this->ColActive) {
6699 $this->breakpoints[$this->CurrCol][] = $this->y;
6700 } // *COLUMNS*
6701 $this->x = $currentx;
6702 }
6703
6704
6705 // Added mPDF 3.0 Float DIV
6706 $fpaddingR = 0;
6707 $fpaddingL = 0;
6708 /* -- CSS-FLOAT -- */
6709 if (count($this->floatDivs)) {
6710 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
6711 if ($r_exists) {
6712 $fpaddingR = $r_width;
6713 }
6714 if ($l_exists) {
6715 $fpaddingL = $l_width;
6716 }
6717 }
6718 /* -- END CSS-FLOAT -- */
6719
6720 $usey = $this->y + 0.002;
6721 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
6722 $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
6723 }
6724 /* -- CSS-IMAGE-FLOAT -- */
6725 // If float exists at this level
6726 if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
6727 $fpaddingR += $this->floatmargins['R']['w'];
6728 }
6729 if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
6730 $fpaddingL += $this->floatmargins['L']['w'];
6731 }
6732 /* -- END CSS-IMAGE-FLOAT -- */
6733
6734
6735 if ($content) {
6736 // In FinishFlowing Block no lines are justified as it is always last line
6737 // but if CJKorphan has allowed content width to go over max width, use J charspacing to compress line
6738 // JUSTIFICATION J - NOT!
6739 $nb_carac = 0;
6740 $nb_spaces = 0;
6741 $jcharspacing = 0;
6742 $jkashida = 0;
6743 $jws = 0;
6744 $inclCursive = false;
6745 $dottab = false;
6746 foreach ($content as $k => $chunk) {
6747 if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
6748 $nb_carac += mb_strlen($chunk, $this->mb_enc);
6749 $nb_spaces += mb_substr_count($chunk, ' ', $this->mb_enc);
6750 // mPDF 6
6751 // Use GPOS OTL
6752 $this->restoreFont($font[$k], false);
6753 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6754 if (isset($cOTLdata[$k]['group']) && $cOTLdata[$k]['group']) {
6755 $nb_marks = substr_count($cOTLdata[$k]['group'], 'M');
6756 $nb_carac -= $nb_marks;
6757 }
6758 if (preg_match("/([" . $this->pregCURSchars . "])/u", $chunk)) {
6759 $inclCursive = true;
6760 }
6761 }
6762 } else {
6763 $nb_carac ++; // mPDF 6 allow spacing for inline object
6764 if ($this->objectbuffer[$k]['type'] == 'dottab') {
6765 $dottab = $this->objectbuffer[$k]['outdent'];
6766 }
6767 }
6768 }
6769
6770 // DIRECTIONALITY RTL
6771 $chunkorder = range(0, count($content) - 1); // mPDF 6
6772 /* -- OTL -- */
6773 // mPDF 6
6774 if ($blockdir == 'rtl' || $this->biDirectional) {
6775 $this->otl->bidiReorder($chunkorder, $content, $cOTLdata, $blockdir);
6776 // From this point on, $content and $cOTLdata may contain more elements (and re-ordered) compared to
6777 // $this->objectbuffer and $font ($chunkorder contains the mapping)
6778 }
6779 /* -- END OTL -- */
6780
6781 // Remove any XAdvance from OTL data at end of line
6782 // And correct for XPlacement on last character
6783 // BIDI is applied
6784 foreach ($chunkorder as $aord => $k) {
6785 if (count($cOTLdata)) {
6786 $this->restoreFont($font[$k], false);
6787 // ...FinishFlowingBlock...
6788 if ($aord == count($chunkorder) - 1 && isset($cOTLdata[$aord]['group'])) { // Last chunk on line
6789 $nGPOS = strlen($cOTLdata[$aord]['group']) - 1; // Last character
6790 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL']) || isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'])) {
6791 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'])) {
6792 $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
6793 } else {
6794 $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
6795 }
6796 $w *= ($this->FontSize / 1000);
6797 $contentWidth -= $w * Mpdf::SCALE;
6798 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = 0;
6799 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = 0;
6800 }
6801
6802 // If last character has an XPlacement set, adjust width calculation, and add to XAdvance to account for it
6803 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'])) {
6804 $w = -$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
6805 $w *= ($this->FontSize / 1000);
6806 $contentWidth -= $w * Mpdf::SCALE;
6807 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
6808 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
6809 }
6810 }
6811 }
6812 }
6813
6814 // if it's justified, we need to find the char/word spacing (or if orphans have allowed length of line to go over the maxwidth)
6815 // If "orphans" in fact is just a final space - ignore this
6816 $lastchar = mb_substr($content[(count($chunkorder) - 1)], mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, 1, $this->mb_enc);
6817 if (preg_match("/[" . $this->CJKoverflow . "]/u", $lastchar)) {
6818 $CJKoverflow = true;
6819 } else {
6820 $CJKoverflow = false;
6821 }
6822 if ((((($contentWidth + $lastitalic) > $maxWidth) && ($content[(count($chunkorder) - 1)] != ' ') ) ||
6823 (!$endofblock && $align == 'J' && ($next == 'image' || $next == 'select' || $next == 'input' || $next == 'textarea' || ($next == 'br' && $this->justifyB4br)))) && !($CJKoverflow && $this->allowCJKoverflow)) {
6824 // WORD SPACING
6825 list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) )), $inclCursive, $cOTLdata);
6826 } /* -- CJK-FONTS -- */ elseif ($this->checkCJK && $align == 'J' && $CJKoverflow && $this->allowCJKoverflow && $this->CJKforceend) {
6827 // force-end overhang
6828 $hanger = mb_substr($content[(count($chunkorder) - 1)], mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, 1, $this->mb_enc);
6829 if (preg_match("/[" . $this->CJKoverflow . "]/u", $hanger)) {
6830 $content[(count($chunkorder) - 1)] = mb_substr($content[(count($chunkorder) - 1)], 0, mb_strlen($content[(count($chunkorder) - 1)], $this->mb_enc) - 1, $this->mb_enc);
6831 $this->restoreFont($font[$chunkorder[count($chunkorder) - 1]], false);
6832 $contentWidth -= $this->GetStringWidth($hanger) * Mpdf::SCALE;
6833 $nb_carac -= 1;
6834 list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) )), $inclCursive, $cOTLdata);
6835 }
6836 } /* -- END CJK-FONTS -- */
6837
6838 // Check if will fit at word/char spacing of previous line - if so continue it
6839 // but only allow a maximum of $this->jSmaxWordLast and $this->jSmaxCharLast
6840 elseif ($contentWidth < ($maxWidth - $lastitalic - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE))) && !$this->fixedlSpacing) {
6841 if ($this->ws > $this->jSmaxWordLast) {
6842 $jws = $this->jSmaxWordLast;
6843 }
6844 if ($this->charspacing > $this->jSmaxCharLast) {
6845 $jcharspacing = $this->jSmaxCharLast;
6846 }
6847 $check = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) ) - ( $jcharspacing * $nb_carac) - ( $jws * $nb_spaces);
6848 if ($check <= 0) {
6849 $jcharspacing = 0;
6850 $jws = 0;
6851 }
6852 }
6853
6854 $empty = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) );
6855
6856
6857 $empty -= ($jcharspacing * ($nb_carac - 1)); // mPDF 6 nb_carac MINUS 1
6858 $empty -= ($jws * $nb_spaces);
6859 $empty -= ($jkashida);
6860
6861 $empty /= Mpdf::SCALE;
6862
6863 if (!$is_table) {
6864 $this->maxPosR = max($this->maxPosR, ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin'] - $empty));
6865 $this->maxPosL = min($this->maxPosL, ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $empty));
6866 }
6867
6868 $arraysize = count($chunkorder);
6869
6870 $margins = ($this->cMarginL + $this->cMarginR) + ($ipaddingL + $ipaddingR + $fpaddingR + $fpaddingR );
6871
6872 if (!$is_table) {
6873 $this->DivLn($stackHeight, $this->blklvl, false);
6874 } // false -> don't advance y
6875
6876 $this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL;
6877 if ($dottab !== false && $blockdir == 'rtl') {
6878 $this->x -= $dottab;
6879 } elseif ($align == 'R') {
6880 $this->x += $empty;
6881 } elseif ($align == 'J' && $blockdir == 'rtl') {
6882 $this->x += $empty;
6883 } elseif ($align == 'C') {
6884 $this->x += ($empty / 2);
6885 }
6886
6887 // Paragraph INDENT
6888 $WidthCorrection = 0;
6889 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
6890 $ti = $this->sizeConverter->convert($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4
6891 if ($blockdir != 'rtl') {
6892 $this->x += $ti;
6893 } // mPDF 6
6894 }
6895
6896 foreach ($chunkorder as $aord => $k) { // mPDF 5.7
6897 $chunk = $content[$aord];
6898 if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
6899 $xadj = $this->x - $this->objectbuffer[$k]['OUTER-X'];
6900 $this->objectbuffer[$k]['OUTER-X'] += $xadj;
6901 $this->objectbuffer[$k]['BORDER-X'] += $xadj;
6902 $this->objectbuffer[$k]['INNER-X'] += $xadj;
6903
6904 if ($this->objectbuffer[$k]['type'] == 'listmarker') {
6905 $this->objectbuffer[$k]['lineBox'] = $lineBox[-1]; // Block element details for glyph-origin
6906 }
6907 $yadj = $this->y - $this->objectbuffer[$k]['OUTER-Y'];
6908 if ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
6909 $this->objectbuffer[$k]['lineBox'] = $lineBox[$k]; // element details for glyph-origin
6910 }
6911 if ($this->objectbuffer[$k]['type'] != 'dottab') { // mPDF 6 DOTTAB
6912 $yadj += $lineBox[$k]['top'];
6913 }
6914 $this->objectbuffer[$k]['OUTER-Y'] += $yadj;
6915 $this->objectbuffer[$k]['BORDER-Y'] += $yadj;
6916 $this->objectbuffer[$k]['INNER-Y'] += $yadj;
6917 }
6918
6919 $this->restoreFont($font[$k]); // mPDF 5.7
6920
6921 if ($is_table && substr($align, 0, 1) == 'D' && $aord == 0) {
6922 $dp = $this->decimal_align[substr($align, 0, 2)];
6923 $s = preg_split('/' . preg_quote($dp, '/') . '/', $content[0], 2); // ? needs to be /u if not core
6924 $s0 = $this->GetStringWidth($s[0], false);
6925 $this->x += ($this->decimal_offset - $s0);
6926 }
6927
6928 $this->SetSpacing(($this->fixedlSpacing * Mpdf::SCALE) + $jcharspacing, ($this->fixedlSpacing + $this->minwSpacing) * Mpdf::SCALE + $jws);
6929 $this->fixedlSpacing = false;
6930 $this->minwSpacing = 0;
6931
6932 $save_vis = $this->visibility;
6933 if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->textparam['visibility'] != $this->visibility) {
6934 $this->SetVisibility($this->textparam['visibility']);
6935 }
6936
6937 // *********** SPAN BACKGROUND COLOR ***************** //
6938 if (isset($this->spanbgcolor) && $this->spanbgcolor) {
6939 $cor = $this->spanbgcolorarray;
6940 $this->SetFColor($cor);
6941 $save_fill = $fill;
6942 $spanfill = 1;
6943 $fill = 1;
6944 }
6945 if (!empty($this->spanborddet)) {
6946 if (strpos($contentB[$k], 'L') !== false && isset($this->spanborddet['L'])) {
6947 $this->x += $this->spanborddet['L']['w'];
6948 }
6949 if (strpos($contentB[$k], 'L') === false) {
6950 $this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0;
6951 }
6952 if (strpos($contentB[$k], 'R') === false) {
6953 $this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0;
6954 }
6955 }
6956 // WORD SPACING
6957 // mPDF 5.7.1
6958 $stringWidth = $this->GetStringWidth($chunk, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar);
6959 $nch = mb_strlen($chunk, $this->mb_enc);
6960 // Use GPOS OTL
6961 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
6962 if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
6963 $nch -= substr_count($cOTLdata[$aord]['group'], 'M');
6964 }
6965 }
6966 $stringWidth += ( $this->charspacing * $nch / Mpdf::SCALE );
6967
6968 $stringWidth += ( $this->ws * mb_substr_count($chunk, ' ', $this->mb_enc) / Mpdf::SCALE );
6969
6970 if (isset($this->objectbuffer[$k])) {
6971 if ($this->objectbuffer[$k]['type'] == 'dottab') {
6972 $this->objectbuffer[$k]['OUTER-WIDTH'] +=$empty;
6973 $this->objectbuffer[$k]['OUTER-WIDTH'] +=$this->objectbuffer[$k]['outdent'];
6974 }
6975 // LIST MARKERS // mPDF 6 Lists
6976 if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
6977 // do nothing
6978 } else {
6979 $stringWidth = $this->objectbuffer[$k]['OUTER-WIDTH'];
6980 }
6981 }
6982
6983 if ($stringWidth == 0) {
6984 $stringWidth = 0.000001;
6985 }
6986 if ($aord == $arraysize - 1) { // mPDF 5.7
6987 // mPDF 5.7.1
6988 if ($this->checkCJK && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) {
6989 // force-end overhang
6990 $this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mPDF 5.7.1
6991 $this->Cell($this->GetStringWidth($hanger), $stackHeight, $hanger, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mPDF 5.7.1
6992 } else {
6993 $this->Cell($stringWidth, $stackHeight, $chunk, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mPDF 5.7.1
6994 }
6995 } else {
6996 $this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, 0, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // first or middle part // mPDF 5.7.1
6997 }
6998
6999
7000 if (!empty($this->spanborddet)) {
7001 if (strpos($contentB[$k], 'R') !== false && $aord != $arraysize - 1) {
7002 $this->x += $this->spanborddet['R']['w'];
7003 }
7004 }
7005 // *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** //
7006 if (isset($spanfill) && $spanfill) {
7007 $fill = $save_fill;
7008 $spanfill = 0;
7009 if ($fill) {
7010 $this->SetFColor($bcor);
7011 }
7012 }
7013 if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->visibility != $save_vis) {
7014 $this->SetVisibility($save_vis);
7015 }
7016 }
7017
7018 $this->printobjectbuffer($is_table, $blockdir);
7019 $this->objectbuffer = [];
7020 $this->ResetSpacing();
7021 } // END IF CONTENT
7022
7023 /* -- CSS-IMAGE-FLOAT -- */
7024 // Update values if set to skipline
7025 if ($this->floatmargins) {
7026 $this->_advanceFloatMargins();
7027 }
7028
7029
7030 if ($endofblock && $blockstate > 1) {
7031 // If float exists at this level
7032 if (isset($this->floatmargins['R']['y1'])) {
7033 $fry1 = $this->floatmargins['R']['y1'];
7034 } else {
7035 $fry1 = 0;
7036 }
7037 if (isset($this->floatmargins['L']['y1'])) {
7038 $fly1 = $this->floatmargins['L']['y1'];
7039 } else {
7040 $fly1 = 0;
7041 }
7042 if ($this->y < $fry1 || $this->y < $fly1) {
7043 $drop = max($fry1, $fly1) - $this->y;
7044 $this->DivLn($drop);
7045 $this->x = $currentx;
7046 }
7047 }
7048 /* -- END CSS-IMAGE-FLOAT -- */
7049
7050
7051 // PADDING and BORDER spacing/fill
7052 if ($endofblock && ($blockstate > 1) && ($this->blk[$this->blklvl]['padding_bottom'] || $this->blk[$this->blklvl]['border_bottom'] || $this->blk[$this->blklvl]['css_set_height']) && (!$is_table)) {
7053 // If CSS height set, extend bottom - if on same page as block started, and CSS HEIGHT > actual height,
7054 // and does not force pagebreak
7055 $extra = 0;
7056 if (isset($this->blk[$this->blklvl]['css_set_height']) && $this->blk[$this->blklvl]['css_set_height'] && $this->blk[$this->blklvl]['startpage'] == $this->page) {
7057 // predicted height
7058 $h1 = ($this->y - $this->blk[$this->blklvl]['y0']) + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'];
7059 if ($h1 < ($this->blk[$this->blklvl]['css_set_height'] + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['padding_top'])) {
7060 $extra = ($this->blk[$this->blklvl]['css_set_height'] + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['padding_top']) - $h1;
7061 }
7062 if ($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra > $this->PageBreakTrigger) {
7063 $extra = $this->PageBreakTrigger - ($this->y + $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w']);
7064 }
7065 }
7066
7067 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
7068 $this->DivLn($this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $extra, -3, true, false, 2);
7069 $this->x = $currentx;
7070
7071 if ($this->ColActive) {
7072 $this->breakpoints[$this->CurrCol][] = $this->y;
7073 } // *COLUMNS*
7074 }
7075
7076 // SET Bottom y1 of block (used for painting borders)
7077 if (($endofblock) && ($blockstate > 1) && (!$is_table)) {
7078 $this->blk[$this->blklvl]['y1'] = $this->y;
7079 }
7080
7081 // BOTTOM MARGIN
7082 if (($endofblock) && ($blockstate > 1) && ($this->blk[$this->blklvl]['margin_bottom']) && (!$is_table)) {
7083 if ($this->y + $this->blk[$this->blklvl]['margin_bottom'] < $this->PageBreakTrigger and ! $this->InFooter) {
7084 $this->DivLn($this->blk[$this->blklvl]['margin_bottom'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
7085 if ($this->ColActive) {
7086 $this->breakpoints[$this->CurrCol][] = $this->y;
7087 } // *COLUMNS*
7088 }
7089 }
7090
7091 // Reset lineheight
7092 $stackHeight = $this->divheight;
7093 }
7094
7095 function printobjectbuffer($is_table = false, $blockdir = false)
7096 {
7097 if (!$blockdir) {
7098 $blockdir = $this->directionality;
7099 }
7100
7101 if ($is_table && $this->shrin_k > 1) {
7102 $k = $this->shrin_k;
7103 } else {
7104 $k = 1;
7105 }
7106
7107 $save_y = $this->y;
7108 $save_x = $this->x;
7109
7110 $save_currentfontfamily = $this->FontFamily;
7111 $save_currentfontsize = $this->FontSizePt;
7112 $save_currentfontstyle = $this->FontStyle;
7113
7114 if ($blockdir == 'rtl') {
7115 $rtlalign = 'R';
7116 } else {
7117 $rtlalign = 'L';
7118 }
7119
7120 foreach ($this->objectbuffer as $ib => $objattr) {
7121
7122 if ($objattr['type'] == 'bookmark' || $objattr['type'] == 'indexentry' || $objattr['type'] == 'toc') {
7123 $x = $objattr['OUTER-X'];
7124 $y = $objattr['OUTER-Y'];
7125 $this->y = $y - $this->FontSize / 2;
7126 $this->x = $x;
7127 if ($objattr['type'] == 'bookmark') {
7128 $this->Bookmark($objattr['CONTENT'], $objattr['bklevel'], $y - $this->FontSize);
7129 } // *BOOKMARKS*
7130 if ($objattr['type'] == 'indexentry') {
7131 $this->IndexEntry($objattr['CONTENT']);
7132 } // *INDEX*
7133 if ($objattr['type'] == 'toc') {
7134 $this->TOC_Entry($objattr['CONTENT'], $objattr['toclevel'], (isset($objattr['toc_id']) ? $objattr['toc_id'] : ''));
7135 } // *TOC*
7136 } /* -- ANNOTATIONS -- */ elseif ($objattr['type'] == 'annot') {
7137 if ($objattr['POS-X']) {
7138 $x = $objattr['POS-X'];
7139 } elseif ($this->annotMargin <> 0) {
7140 $x = -$objattr['OUTER-X'];
7141 } else {
7142 $x = $objattr['OUTER-X'];
7143 }
7144 if ($objattr['POS-Y']) {
7145 $y = $objattr['POS-Y'];
7146 } else {
7147 $y = $objattr['OUTER-Y'] - $this->FontSize / 2;
7148 }
7149 // Create a dummy entry in the _out/columnBuffer with position sensitive data,
7150 // linking $y-1 in the Columnbuffer with entry in $this->columnAnnots
7151 // and when columns are split in length will not break annotation from current line
7152 $this->y = $y - 1;
7153 $this->x = $x - 1;
7154 $this->Line($x - 1, $y - 1, $x - 1, $y - 1);
7155 $this->Annotation($objattr['CONTENT'], $x, $y, $objattr['ICON'], $objattr['AUTHOR'], $objattr['SUBJECT'], $objattr['OPACITY'], $objattr['COLOR'], (isset($objattr['POPUP']) ? $objattr['POPUP'] : ''), (isset($objattr['FILE']) ? $objattr['FILE'] : ''));
7156 } /* -- END ANNOTATIONS -- */ else {
7157 $y = $objattr['OUTER-Y'];
7158 $x = $objattr['OUTER-X'];
7159 $w = $objattr['OUTER-WIDTH'];
7160 $h = $objattr['OUTER-HEIGHT'];
7161 if (isset($objattr['text'])) {
7162 $texto = $objattr['text'];
7163 }
7164 $this->y = $y;
7165 $this->x = $x;
7166 if (isset($objattr['fontfamily'])) {
7167 $this->SetFont($objattr['fontfamily'], '', $objattr['fontsize']);
7168 }
7169 }
7170
7171 // HR
7172 if ($objattr['type'] == 'hr') {
7173 $this->SetDColor($objattr['color']);
7174 switch ($objattr['align']) {
7175 case 'C':
7176 $empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH'];
7177 $empty /= 2;
7178 $x += $empty;
7179 break;
7180 case 'R':
7181 $empty = $objattr['OUTER-WIDTH'] - $objattr['INNER-WIDTH'];
7182 $x += $empty;
7183 break;
7184 }
7185 $oldlinewidth = $this->LineWidth;
7186 $this->SetLineWidth($objattr['linewidth'] / $k);
7187 $this->y += ($objattr['linewidth'] / 2) + $objattr['margin_top'] / $k;
7188 $this->Line($x, $this->y, $x + $objattr['INNER-WIDTH'], $this->y);
7189 $this->SetLineWidth($oldlinewidth);
7190 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
7191 }
7192 // IMAGE
7193 if ($objattr['type'] == 'image') {
7194 // mPDF 5.7.3 TRANSFORMS
7195 if (isset($objattr['transform'])) {
7196 $this->writer->write("\n" . '% BTR'); // Begin Transform
7197 }
7198 if (isset($objattr['z-index']) && $objattr['z-index'] > 0 && $this->current_layer == 0) {
7199 $this->BeginLayer($objattr['z-index']);
7200 }
7201 if (isset($objattr['visibility']) && $objattr['visibility'] != 'visible' && $objattr['visibility']) {
7202 $this->SetVisibility($objattr['visibility']);
7203 }
7204 if (isset($objattr['opacity'])) {
7205 $this->SetAlpha($objattr['opacity']);
7206 }
7207
7208 $obiw = $objattr['INNER-WIDTH'];
7209 $obih = $objattr['INNER-HEIGHT'];
7210
7211 $sx = $objattr['orig_w'] ? ($objattr['INNER-WIDTH'] * Mpdf::SCALE / $objattr['orig_w']) : INF;
7212 $sy = $objattr['orig_h'] ? ($objattr['INNER-HEIGHT'] * Mpdf::SCALE / $objattr['orig_h']) : INF;
7213
7214 $rotate = 0;
7215 if (isset($objattr['ROTATE'])) {
7216 $rotate = $objattr['ROTATE'];
7217 }
7218
7219 if ($rotate == 90) {
7220 // Clockwise
7221 $obiw = $objattr['INNER-HEIGHT'];
7222 $obih = $objattr['INNER-WIDTH'];
7223 $tr = $this->transformTranslate(0, -$objattr['INNER-WIDTH'], true);
7224 $tr .= ' ' . $this->transformRotate(90, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-WIDTH']), true);
7225 $sx = $obiw * Mpdf::SCALE / $objattr['orig_h'];
7226 $sy = $obih * Mpdf::SCALE / $objattr['orig_w'];
7227 } elseif ($rotate == -90 || $rotate == 270) {
7228 // AntiClockwise
7229 $obiw = $objattr['INNER-HEIGHT'];
7230 $obih = $objattr['INNER-WIDTH'];
7231 $tr = $this->transformTranslate($objattr['INNER-WIDTH'], ($objattr['INNER-HEIGHT'] - $objattr['INNER-WIDTH']), true);
7232 $tr .= ' ' . $this->transformRotate(-90, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-WIDTH']), true);
7233 $sx = $obiw * Mpdf::SCALE / $objattr['orig_h'];
7234 $sy = $obih * Mpdf::SCALE / $objattr['orig_w'];
7235 } elseif ($rotate == 180) {
7236 // Mirror
7237 $tr = $this->transformTranslate($objattr['INNER-WIDTH'], -$objattr['INNER-HEIGHT'], true);
7238 $tr .= ' ' . $this->transformRotate(180, $objattr['INNER-X'], ($objattr['INNER-Y'] + $objattr['INNER-HEIGHT']), true);
7239 } else {
7240 $tr = '';
7241 }
7242 $tr = trim($tr);
7243 if ($tr) {
7244 $tr .= ' ';
7245 }
7246 $gradmask = '';
7247
7248 // mPDF 5.7.3 TRANSFORMS
7249 $tr2 = '';
7250 if (isset($objattr['transform'])) {
7251 $maxsize_x = $w;
7252 $maxsize_y = $h;
7253 $cx = $x + $w / 2;
7254 $cy = $y + $h / 2;
7255 preg_match_all('/(translatex|translatey|translate|scalex|scaley|scale|rotate|skewX|skewY|skew)\‍((.*?)\‍)/is', $objattr['transform'], $m);
7256 if (count($m[0])) {
7257 for ($i = 0; $i < count($m[0]); $i++) {
7258 $c = strtolower($m[1][$i]);
7259 $v = trim($m[2][$i]);
7260 $vv = preg_split('/[ ,]+/', $v);
7261 if ($c == 'translate' && count($vv)) {
7262 $translate_x = $this->sizeConverter->convert($vv[0], $maxsize_x, false, false);
7263 if (count($vv) == 2) {
7264 $translate_y = $this->sizeConverter->convert($vv[1], $maxsize_y, false, false);
7265 } else {
7266 $translate_y = 0;
7267 }
7268 $tr2 .= $this->transformTranslate($translate_x, $translate_y, true) . ' ';
7269 } elseif ($c == 'translatex' && count($vv)) {
7270 $translate_x = $this->sizeConverter->convert($vv[0], $maxsize_x, false, false);
7271 $tr2 .= $this->transformTranslate($translate_x, 0, true) . ' ';
7272 } elseif ($c == 'translatey' && count($vv)) {
7273 $translate_y = $this->sizeConverter->convert($vv[1], $maxsize_y, false, false);
7274 $tr2 .= $this->transformTranslate(0, $translate_y, true) . ' ';
7275 } elseif ($c == 'scale' && count($vv)) {
7276 $scale_x = $vv[0] * 100;
7277 if (count($vv) == 2) {
7278 $scale_y = $vv[1] * 100;
7279 } else {
7280 $scale_y = $scale_x;
7281 }
7282 $tr2 .= $this->transformScale($scale_x, $scale_y, $cx, $cy, true) . ' ';
7283 } elseif ($c == 'scalex' && count($vv)) {
7284 $scale_x = $vv[0] * 100;
7285 $tr2 .= $this->transformScale($scale_x, 0, $cx, $cy, true) . ' ';
7286 } elseif ($c == 'scaley' && count($vv)) {
7287 $scale_y = $vv[1] * 100;
7288 $tr2 .= $this->transformScale(0, $scale_y, $cx, $cy, true) . ' ';
7289 } elseif ($c == 'skew' && count($vv)) {
7290 $angle_x = $this->ConvertAngle($vv[0], false);
7291 if (count($vv) == 2) {
7292 $angle_y = $this->ConvertAngle($vv[1], false);
7293 } else {
7294 $angle_y = 0;
7295 }
7296 $tr2 .= $this->transformSkew($angle_x, $angle_y, $cx, $cy, true) . ' ';
7297 } elseif ($c == 'skewx' && count($vv)) {
7298 $angle = $this->ConvertAngle($vv[0], false);
7299 $tr2 .= $this->transformSkew($angle, 0, $cx, $cy, true) . ' ';
7300 } elseif ($c == 'skewy' && count($vv)) {
7301 $angle = $this->ConvertAngle($vv[0], false);
7302 $tr2 .= $this->transformSkew(0, $angle, $cx, $cy, true) . ' ';
7303 } elseif ($c == 'rotate' && count($vv)) {
7304 $angle = $this->ConvertAngle($vv[0]);
7305 $tr2 .= $this->transformRotate($angle, $cx, $cy, true) . ' ';
7306 }
7307 }
7308 }
7309 }
7310
7311 // LIST MARKERS (Images) // mPDF 6 Lists
7312 if (isset($objattr['listmarker']) && $objattr['listmarker'] && $objattr['listmarkerposition'] == 'outside') {
7313 $mw = $objattr['OUTER-WIDTH'];
7314 // NB If change marker-offset, also need to alter in function _getListMarkerWidth
7315 $adjx = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
7316 if ($objattr['dir'] == 'rtl') {
7317 $objattr['INNER-X'] += $adjx;
7318 } else {
7319 $objattr['INNER-X'] -= $adjx;
7320 $objattr['INNER-X'] -= $mw;
7321 }
7322 }
7323 // mPDF 5.7.3 TRANSFORMS / BACKGROUND COLOR
7324 // Transform also affects image background
7325 if ($tr2) {
7326 $this->writer->write('q ' . $tr2 . ' ');
7327 }
7328 if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
7329 $bgcol = $objattr['bgcolor'];
7330 $this->SetFColor($bgcol);
7331 $this->Rect($x, $y, $w, $h, 'F');
7332 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
7333 }
7334 if ($tr2) {
7335 $this->writer->write('Q');
7336 }
7337
7338 /* -- BACKGROUNDS -- */
7339 if (isset($objattr['GRADIENT-MASK'])) {
7340 $g = $this->gradient->parseMozGradient($objattr['GRADIENT-MASK']);
7341 if ($g) {
7342 $dummy = $this->gradient->Gradient($objattr['INNER-X'], $objattr['INNER-Y'], $obiw, $obih, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend'], true, true);
7343 $gradmask = '/TGS' . count($this->gradients) . ' gs ';
7344 }
7345 }
7346 /* -- END BACKGROUNDS -- */
7347 /* -- IMAGES-WMF -- */
7348 if (isset($objattr['itype']) && $objattr['itype'] == 'wmf') {
7349 $outstring = sprintf('q ' . $tr . $tr2 . '%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X'] * Mpdf::SCALE - $sx * $objattr['wmf_x'], (($this->h - $objattr['INNER-Y']) * Mpdf::SCALE) + $sy * $objattr['wmf_y'], $objattr['ID']); // mPDF 5.7.3 TRANSFORMS
7350 } else { /* -- END IMAGES-WMF -- */
7351 if (isset($objattr['itype']) && $objattr['itype'] == 'svg') {
7352 $outstring = sprintf('q ' . $tr . $tr2 . '%.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, -$sy, $objattr['INNER-X'] * Mpdf::SCALE - $sx * $objattr['wmf_x'], (($this->h - $objattr['INNER-Y']) * Mpdf::SCALE) + $sy * $objattr['wmf_y'], $objattr['ID']); // mPDF 5.7.3 TRANSFORMS
7353 } else {
7354 $outstring = sprintf("q " . $tr . $tr2 . "%.3F 0 0 %.3F %.3F %.3F cm " . $gradmask . "/I%d Do Q", $obiw * Mpdf::SCALE, $obih * Mpdf::SCALE, $objattr['INNER-X'] * Mpdf::SCALE, ($this->h - ($objattr['INNER-Y'] + $obih )) * Mpdf::SCALE, $objattr['ID']); // mPDF 5.7.3 TRANSFORMS
7355 }
7356 }
7357 $this->writer->write($outstring);
7358 // LINK
7359 if (isset($objattr['link'])) {
7360 $this->Link($objattr['INNER-X'], $objattr['INNER-Y'], $objattr['INNER-WIDTH'], $objattr['INNER-HEIGHT'], $objattr['link']);
7361 }
7362 if (isset($objattr['opacity'])) {
7363 $this->SetAlpha(1);
7364 }
7365
7366 // mPDF 5.7.3 TRANSFORMS
7367 // Transform also affects image borders
7368 if ($tr2) {
7369 $this->writer->write('q ' . $tr2 . ' ');
7370 }
7371 if ((isset($objattr['border_top']) && $objattr['border_top'] > 0) || (isset($objattr['border_left']) && $objattr['border_left'] > 0) || (isset($objattr['border_right']) && $objattr['border_right'] > 0) || (isset($objattr['border_bottom']) && $objattr['border_bottom'] > 0)) {
7372 $this->PaintImgBorder($objattr, $is_table);
7373 }
7374 if ($tr2) {
7375 $this->writer->write('Q');
7376 }
7377
7378 if (isset($objattr['visibility']) && $objattr['visibility'] != 'visible' && $objattr['visibility']) {
7379 $this->SetVisibility('visible');
7380 }
7381 if (isset($objattr['z-index']) && $objattr['z-index'] > 0 && $this->current_layer == 0) {
7382 $this->EndLayer();
7383 }
7384 // mPDF 5.7.3 TRANSFORMS
7385 if (isset($objattr['transform'])) {
7386 $this->writer->write("\n" . '% ETR'); // End Transform
7387 }
7388 }
7389
7390 if ($objattr['type'] === 'barcode') {
7391
7392 $bgcol = $this->colorConverter->convert(255, $this->PDFAXwarnings);
7393
7394 if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
7395 $bgcol = $objattr['bgcolor'];
7396 }
7397
7398 $col = $this->colorConverter->convert(0, $this->PDFAXwarnings);
7399
7400 if (isset($objattr['color']) && $objattr['color']) {
7401 $col = $objattr['color'];
7402 }
7403
7404 $this->SetFColor($bgcol);
7405 $this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F');
7406 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
7407
7408 if (isset($objattr['BORDER-WIDTH'])) {
7409 $this->PaintImgBorder($objattr, $is_table);
7410 }
7411
7412 $barcodeTypes = ['EAN13', 'ISBN', 'ISSN', 'UPCA', 'UPCE', 'EAN8'];
7413 if (in_array($objattr['btype'], $barcodeTypes, true)) {
7414
7415 $this->WriteBarcode(
7416 $objattr['code'],
7417 $objattr['showtext'],
7418 $objattr['INNER-X'],
7419 $objattr['INNER-Y'],
7420 $objattr['bsize'],
7421 0,
7422 0,
7423 0,
7424 0,
7425 0,
7426 $objattr['bheight'],
7427 $bgcol,
7428 $col,
7429 $objattr['btype'],
7430 $objattr['bsupp'],
7431 (isset($objattr['bsupp_code']) ? $objattr['bsupp_code'] : ''),
7432 $k
7433 );
7434
7435 } elseif ($objattr['btype'] === 'QR') {
7436
7437 if (!class_exists('Mpdf\QrCode\QrCode') || !class_exists('Mpdf\QrCode\Output\Mpdf')) {
7438 throw new \Mpdf\MpdfException('Mpdf\QrCode package was not found. Install the package from Packagist with "composer require mpdf/qrcode"');
7439 }
7440
7441 $barcodeContent = str_replace('\r\n', "\r\n", $objattr['code']);
7442 $barcodeContent = str_replace('\n', "\n", $barcodeContent);
7443
7444 $qrcode = new QrCode\QrCode($barcodeContent, $objattr['errorlevel']);
7445 if ($objattr['disableborder']) {
7446 $qrcode->disableBorder();
7447 }
7448
7449 $bgColor = [255, 255, 255];
7450 if ($objattr['bgcolor']) {
7451 $bgColor = array_map(
7452 function ($col) {
7453 return intval(255 * floatval($col));
7454 },
7455 explode(" ", $this->SetColor($objattr['bgcolor'], 'CodeOnly'))
7456 );
7457 }
7458 $color = [0, 0, 0];
7459 if ($objattr['color']) {
7460 $color = array_map(
7461 function ($col) {
7462 return intval(255 * floatval($col));
7463 },
7464 explode(" ", $this->SetColor($objattr['color'], 'CodeOnly'))
7465 );
7466 }
7467
7468 $out = new QrCode\Output\Mpdf();
7469 $out->output(
7470 $qrcode,
7471 $this,
7472 $objattr['INNER-X'],
7473 $objattr['INNER-Y'],
7474 $objattr['bsize'] * 25,
7475 $bgColor,
7476 $color
7477 );
7478
7479 unset($qrcode);
7480
7481 } else {
7482 $this->WriteBarcode2(
7483 $objattr['code'],
7484 $objattr['INNER-X'],
7485 $objattr['INNER-Y'],
7486 $objattr['bsize'],
7487 $objattr['bheight'],
7488 $bgcol,
7489 $col,
7490 $objattr['btype'],
7491 $objattr['pr_ratio'],
7492 $k,
7493 $objattr['quiet_zone_left'],
7494 $objattr['quiet_zone_right']
7495 );
7496 }
7497 }
7498
7499 // TEXT CIRCLE
7500 if ($objattr['type'] == 'textcircle') {
7501 $bgcol = '';
7502 if (isset($objattr['bgcolor']) && $objattr['bgcolor']) {
7503 $bgcol = $objattr['bgcolor'];
7504 }
7505 $col = $this->colorConverter->convert(0, $this->PDFAXwarnings);
7506 if (isset($objattr['color']) && $objattr['color']) {
7507 $col = $objattr['color'];
7508 }
7509 $this->SetTColor($col);
7510 $this->SetFColor($bgcol);
7511 if ($bgcol) {
7512 $this->Rect($objattr['BORDER-X'], $objattr['BORDER-Y'], $objattr['BORDER-WIDTH'], $objattr['BORDER-HEIGHT'], 'F');
7513 }
7514 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
7515 if (isset($objattr['BORDER-WIDTH'])) {
7516 $this->PaintImgBorder($objattr, $is_table);
7517 }
7518 if (empty($this->directWrite)) {
7519 $this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
7520 }
7521 if (isset($objattr['top-text'])) {
7522 $this->directWrite->CircularText($objattr['INNER-X'] + $objattr['INNER-WIDTH'] / 2, $objattr['INNER-Y'] + $objattr['INNER-HEIGHT'] / 2, $objattr['r'] / $k, $objattr['top-text'], 'top', $objattr['fontfamily'], $objattr['fontsize'] / $k, $objattr['fontstyle'], $objattr['space-width'], $objattr['char-width'], (isset($objattr['divider']) ? $objattr['divider'] : ''));
7523 }
7524 if (isset($objattr['bottom-text'])) {
7525 $this->directWrite->CircularText($objattr['INNER-X'] + $objattr['INNER-WIDTH'] / 2, $objattr['INNER-Y'] + $objattr['INNER-HEIGHT'] / 2, $objattr['r'] / $k, $objattr['bottom-text'], 'bottom', $objattr['fontfamily'], $objattr['fontsize'] / $k, $objattr['fontstyle'], $objattr['space-width'], $objattr['char-width'], (isset($objattr['divider']) ? $objattr['divider'] : ''));
7526 }
7527 }
7528
7529 $this->ResetSpacing();
7530
7531 // LIST MARKERS (Text or bullets) // mPDF 6 Lists
7532 if ($objattr['type'] == 'listmarker') {
7533 if (isset($objattr['fontfamily'])) {
7534 $this->SetFont($objattr['fontfamily'], $objattr['fontstyle'], $objattr['fontsizept']);
7535 }
7536 $col = $this->colorConverter->convert(0, $this->PDFAXwarnings);
7537 if (isset($objattr['colorarray']) && ($objattr['colorarray'])) {
7538 $col = $objattr['colorarray'];
7539 }
7540
7541 if (isset($objattr['bullet']) && $objattr['bullet']) { // Used for position "outside" only
7542 $type = $objattr['bullet'];
7543 $size = $objattr['size'];
7544
7545 if ($objattr['listmarkerposition'] == 'inside') {
7546 $adjx = $size / 2;
7547 if ($objattr['dir'] == 'rtl') {
7548 $adjx += $objattr['offset'];
7549 }
7550 $this->x += $adjx;
7551 } else {
7552 $adjx = $objattr['offset'];
7553 $adjx += $size / 2;
7554 if ($objattr['dir'] == 'rtl') {
7555 $this->x += $adjx;
7556 } else {
7557 $this->x -= $adjx;
7558 }
7559 }
7560
7561 $yadj = $objattr['lineBox']['glyphYorigin'];
7562 if (isset($this->CurrentFont['desc']['XHeight']) && $this->CurrentFont['desc']['XHeight']) {
7563 $xh = $this->CurrentFont['desc']['XHeight'];
7564 } else {
7565 $xh = 500;
7566 }
7567 $yadj -= ($this->FontSize * $xh / 1000) * 0.625; // Vertical height of bullet (centre) from baseline= XHeight * 0.625
7568 $this->y += $yadj;
7569
7570 $this->_printListBullet($this->x, $this->y, $size, $type, $col);
7571 } else {
7572 $this->SetTColor($col);
7573 $w = $this->GetStringWidth($texto);
7574 // NB If change marker-offset, also need to alter in function _getListMarkerWidth
7575 $adjx = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
7576 if ($objattr['dir'] == 'rtl') {
7577 $align = 'L';
7578 $this->x += $adjx;
7579 } else {
7580 // Use these lines to set as marker-offset, right-aligned - default
7581 $align = 'R';
7582 $this->x -= $adjx;
7583 $this->x -= $w;
7584 }
7585 $this->Cell($w, $this->FontSize, $texto, 0, 0, $align, 0, '', 0, 0, 0, 'T', 0, false, false, 0, $objattr['lineBox']);
7586 $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
7587 }
7588 }
7589
7590 // DOT-TAB
7591 if ($objattr['type'] == 'dottab') {
7592 if (isset($objattr['fontfamily'])) {
7593 $this->SetFont($objattr['fontfamily'], '', $objattr['fontsize']);
7594 }
7595 $sp = $this->GetStringWidth(' ');
7596 $nb = floor(($w - 2 * $sp) / $this->GetStringWidth('.'));
7597 if ($nb > 0) {
7598 $dots = ' ' . str_repeat('.', $nb) . ' ';
7599 } else {
7600 $dots = ' ';
7601 }
7602 $col = $this->colorConverter->convert(0, $this->PDFAXwarnings);
7603 if (isset($objattr['colorarray']) && ($objattr['colorarray'])) {
7604 $col = $objattr['colorarray'];
7605 }
7606 $this->SetTColor($col);
7607 $save_dh = $this->divheight;
7608 $save_sbd = $this->spanborddet;
7609 $save_textvar = $this->textvar; // mPDF 5.7.1
7610 $this->spanborddet = '';
7611 $this->divheight = 0;
7612 $this->textvar = 0x00; // mPDF 5.7.1
7613
7614 $this->Cell($w, $h, $dots, 0, 0, 'C', 0, '', 0, 0, 0, 'T', 0, false, false, 0, $objattr['lineBox']); // mPDF 6 DOTTAB
7615 $this->spanborddet = $save_sbd;
7616 $this->textvar = $save_textvar; // mPDF 5.7.1
7617 $this->divheight = $save_dh;
7618 $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
7619 }
7620
7621 /* -- FORMS -- */
7622 // TEXT/PASSWORD INPUT
7623 if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD')) {
7624 $this->form->print_ob_text($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7625 }
7626
7627 // TEXTAREA
7628 if ($objattr['type'] == 'textarea') {
7629 $this->form->print_ob_textarea($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7630 }
7631
7632 // SELECT
7633 if ($objattr['type'] == 'select') {
7634 $this->form->print_ob_select($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7635 }
7636
7637
7638 // INPUT/BUTTON as IMAGE
7639 if ($objattr['type'] == 'input' && $objattr['subtype'] == 'IMAGE') {
7640 $this->form->print_ob_imageinput($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $is_table);
7641 }
7642
7643 // BUTTON
7644 if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'SUBMIT' || $objattr['subtype'] == 'RESET' || $objattr['subtype'] == 'BUTTON')) {
7645 $this->form->print_ob_button($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir);
7646 }
7647
7648 // CHECKBOX
7649 if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'CHECKBOX')) {
7650 $this->form->print_ob_checkbox($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y);
7651 }
7652 // RADIO
7653 if ($objattr['type'] == 'input' && ($objattr['subtype'] == 'RADIO')) {
7654 $this->form->print_ob_radio($objattr, $w, $h, $texto, $rtlalign, $k, $blockdir, $x, $y);
7655 }
7656 /* -- END FORMS -- */
7657 }
7658
7659 $this->SetFont($save_currentfontfamily, $save_currentfontstyle, $save_currentfontsize);
7660
7661 $this->y = $save_y;
7662 $this->x = $save_x;
7663
7664 unset($content);
7665 }
7666
7667 function _printListBullet($x, $y, $size, $type, $color)
7668 {
7669 // x and y are the centre of the bullet; size is the width and/or height in mm
7670 $fcol = $this->SetTColor($color, true);
7671 $lcol = strtoupper($fcol); // change 0 0 0 rg to 0 0 0 RG
7672 $this->writer->write(sprintf('q %s %s', $lcol, $fcol));
7673 $this->writer->write('0 j 0 J [] 0 d');
7674 if ($type == 'square') {
7675 $size *= 0.85; // Smaller to appear the same size as circle/disc
7676 $this->writer->write(sprintf('%.3F %.3F %.3F %.3F re f', ($x - $size / 2) * Mpdf::SCALE, ($this->h - $y + $size / 2) * Mpdf::SCALE, ($size) * Mpdf::SCALE, (-$size) * Mpdf::SCALE));
7677 } elseif ($type == 'disc') {
7678 $this->Circle($x, $y, $size / 2, 'F'); // Fill
7679 } elseif ($type == 'circle') {
7680 $lw = $size / 12; // Line width
7681 $this->writer->write(sprintf('%.3F w ', $lw * Mpdf::SCALE));
7682 $this->Circle($x, $y, $size / 2 - $lw / 2, 'S'); // Stroke
7683 }
7684 $this->writer->write('Q');
7685 }
7686
7687 // mPDF 6
7688 // Get previous character and move pointers
7689 function _moveToPrevChar(&$contentctr, &$charctr, $content)
7690 {
7691 $lastchar = false;
7692 $charctr--;
7693 while ($charctr < 0) { // go back to previous $content[]
7694 $contentctr--;
7695 if ($contentctr < 0) {
7696 return false;
7697 }
7698 if ($this->usingCoreFont) {
7699 $charctr = strlen($content[$contentctr]) - 1;
7700 } else {
7701 $charctr = mb_strlen($content[$contentctr], $this->mb_enc) - 1;
7702 }
7703 }
7704 if ($this->usingCoreFont) {
7705 $lastchar = $content[$contentctr][$charctr];
7706 } else {
7707 $lastchar = mb_substr($content[$contentctr], $charctr, 1, $this->mb_enc);
7708 }
7709 return $lastchar;
7710 }
7711
7712 // Get previous character
7713 function _getPrevChar($contentctr, $charctr, $content)
7714 {
7715 $lastchar = false;
7716 $charctr--;
7717 while ($charctr < 0) { // go back to previous $content[]
7718 $contentctr--;
7719 if ($contentctr < 0) {
7720 return false;
7721 }
7722 if ($this->usingCoreFont) {
7723 $charctr = strlen($content[$contentctr]) - 1;
7724 } else {
7725 $charctr = mb_strlen($content[$contentctr], $this->mb_enc) - 1;
7726 }
7727 }
7728 if ($this->usingCoreFont) {
7729 $lastchar = $content[$contentctr][$charctr];
7730 } else {
7731 $lastchar = mb_substr($content[$contentctr], $charctr, 1, $this->mb_enc);
7732 }
7733 return $lastchar;
7734 }
7735
7736 function WriteFlowingBlock($s, $sOTLdata)
7737 {
7738 // mPDF 5.7.1
7739 $currentx = $this->x;
7740 $is_table = $this->flowingBlockAttr['is_table'];
7741 $table_draft = $this->flowingBlockAttr['table_draft'];
7742 // width of all the content so far in points
7743 $contentWidth = & $this->flowingBlockAttr['contentWidth'];
7744 // cell width in points
7745 $maxWidth = & $this->flowingBlockAttr['width'];
7746 $lineCount = & $this->flowingBlockAttr['lineCount'];
7747 // line height in user units
7748 $stackHeight = & $this->flowingBlockAttr['height'];
7749 $align = & $this->flowingBlockAttr['align'];
7750 $content = & $this->flowingBlockAttr['content'];
7751 $contentB = & $this->flowingBlockAttr['contentB'];
7752 $font = & $this->flowingBlockAttr['font'];
7753 $valign = & $this->flowingBlockAttr['valign'];
7754 $blockstate = $this->flowingBlockAttr['blockstate'];
7755 $cOTLdata = & $this->flowingBlockAttr['cOTLdata']; // mPDF 5.7.1
7756
7757 $newblock = $this->flowingBlockAttr['newblock'];
7758 $blockdir = $this->flowingBlockAttr['blockdir'];
7759
7760 // *********** BLOCK BACKGROUND COLOR ***************** //
7761 if ($this->blk[$this->blklvl]['bgcolor'] && !$is_table) {
7762 $fill = 0;
7763 } else {
7764 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
7765 $fill = 0;
7766 }
7767 $font[] = $this->saveFont();
7768 $content[] = '';
7769 $contentB[] = '';
7770 $cOTLdata[] = $sOTLdata; // mPDF 5.7.1
7771 $currContent = & $content[count($content) - 1];
7772
7773 $CJKoverflow = false;
7774 $Oikomi = false; // mPDF 6
7775 $hanger = '';
7776
7777 // COLS
7778 $oldcolumn = $this->CurrCol;
7779 if ($this->ColActive && !$is_table) {
7780 $this->breakpoints[$this->CurrCol][] = $this->y;
7781 } // *COLUMNS*
7782
7783 /* -- TABLES -- */
7784 if ($is_table) {
7785 $ipaddingL = 0;
7786 $ipaddingR = 0;
7787 $paddingL = 0;
7788 $paddingR = 0;
7789 $cpaddingadjustL = 0;
7790 $cpaddingadjustR = 0;
7791 // Added mPDF 3.0
7792 $fpaddingR = 0;
7793 $fpaddingL = 0;
7794 } else {
7795 /* -- END TABLES -- */
7796 $ipaddingL = $this->blk[$this->blklvl]['padding_left'];
7797 $ipaddingR = $this->blk[$this->blklvl]['padding_right'];
7798 $paddingL = ($ipaddingL * Mpdf::SCALE);
7799 $paddingR = ($ipaddingR * Mpdf::SCALE);
7800 $this->cMarginL = $this->blk[$this->blklvl]['border_left']['w'];
7801 $cpaddingadjustL = -$this->cMarginL;
7802 $this->cMarginR = $this->blk[$this->blklvl]['border_right']['w'];
7803 $cpaddingadjustR = -$this->cMarginR;
7804 // Added mPDF 3.0 Float DIV
7805 $fpaddingR = 0;
7806 $fpaddingL = 0;
7807 /* -- CSS-FLOAT -- */
7808 if (count($this->floatDivs)) {
7809 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
7810 if ($r_exists) {
7811 $fpaddingR = $r_width;
7812 }
7813 if ($l_exists) {
7814 $fpaddingL = $l_width;
7815 }
7816 }
7817 /* -- END CSS-FLOAT -- */
7818
7819 $usey = $this->y + 0.002;
7820 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
7821 $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
7822 }
7823 /* -- CSS-IMAGE-FLOAT -- */
7824 // If float exists at this level
7825 if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
7826 $fpaddingR += $this->floatmargins['R']['w'];
7827 }
7828 if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
7829 $fpaddingL += $this->floatmargins['L']['w'];
7830 }
7831 /* -- END CSS-IMAGE-FLOAT -- */
7832 } // *TABLES*
7833 // OBJECTS - IMAGES & FORM Elements (NB has already skipped line/page if required - in printbuffer)
7834 if (substr($s, 0, 3) == "\xbb\xa4\xac") { // identifier has been identified!
7835 $objattr = $this->_getObjAttr($s);
7836 $h_corr = 0;
7837 if ($is_table) { // *TABLES*
7838 $maximumW = ($maxWidth / Mpdf::SCALE) - ($this->cellPaddingL + $this->cMarginL + $this->cellPaddingR + $this->cMarginR); // *TABLES*
7839 } // *TABLES*
7840 else { // *TABLES*
7841 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0) && (!$is_table)) {
7842 $h_corr = $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
7843 }
7844 $maximumW = ($maxWidth / Mpdf::SCALE) - ($this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_right'] + $this->blk[$this->blklvl]['border_right']['w'] + $fpaddingL + $fpaddingR );
7845 } // *TABLES*
7846 $objattr = $this->inlineObject($objattr['type'], $this->lMargin + $fpaddingL + ($contentWidth / Mpdf::SCALE), ($this->y + $h_corr), $objattr, $this->lMargin, ($contentWidth / Mpdf::SCALE), $maximumW, $stackHeight, true, $is_table);
7847
7848 // SET LINEHEIGHT for this line ================ RESET AT END
7849 $stackHeight = max($stackHeight, $objattr['OUTER-HEIGHT']);
7850 $this->objectbuffer[count($content) - 1] = $objattr;
7851 // if (isset($objattr['vertical-align'])) { $valign = $objattr['vertical-align']; }
7852 // else { $valign = ''; }
7853 // LIST MARKERS // mPDF 6 Lists
7854 if ($objattr['type'] == 'image' && isset($objattr['listmarker']) && $objattr['listmarker'] && $objattr['listmarkerposition'] == 'outside') {
7855 // do nothing
7856 } else {
7857 $contentWidth += ($objattr['OUTER-WIDTH'] * Mpdf::SCALE);
7858 }
7859 return;
7860 }
7861
7862 $lbw = $rbw = 0; // Border widths
7863 if (!empty($this->spanborddet)) {
7864 if (isset($this->spanborddet['L'])) {
7865 $lbw = $this->spanborddet['L']['w'];
7866 }
7867 if (isset($this->spanborddet['R'])) {
7868 $rbw = $this->spanborddet['R']['w'];
7869 }
7870 }
7871
7872 if ($this->usingCoreFont) {
7873 $clen = strlen($s);
7874 } else {
7875 $clen = mb_strlen($s, $this->mb_enc);
7876 }
7877
7878 // for every character in the string
7879 for ($i = 0; $i < $clen; $i++) {
7880 // extract the current character
7881 // get the width of the character in points
7882 if ($this->usingCoreFont) {
7883 $c = $s[$i];
7884 // Soft Hyphens chr(173)
7885 $cw = ($this->GetCharWidthCore($c) * Mpdf::SCALE);
7886 if (($this->textvar & TextVars::FC_KERNING) && $i > 0) { // mPDF 5.7.1
7887 if (isset($this->CurrentFont['kerninfo'][$s[($i - 1)]][$c])) {
7888 $cw += ($this->CurrentFont['kerninfo'][$s[($i - 1)]][$c] * $this->FontSizePt / 1000 );
7889 }
7890 }
7891 } else {
7892 $c = mb_substr($s, $i, 1, $this->mb_enc);
7893 $cw = ($this->GetCharWidthNonCore($c, false) * Mpdf::SCALE);
7894 // mPDF 5.7.1
7895 // Use OTL GPOS
7896 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
7897 // ...WriteFlowingBlock...
7898 // Only add XAdvanceL (not sure at present whether RTL or LTR writing direction)
7899 // At this point, XAdvanceL and XAdvanceR will balance
7900 if (isset($sOTLdata['GPOSinfo'][$i]['XAdvanceL'])) {
7901 $cw += $sOTLdata['GPOSinfo'][$i]['XAdvanceL'] * (1000 / $this->CurrentFont['unitsPerEm']) * ($this->FontSize / 1000) * Mpdf::SCALE;
7902 }
7903 }
7904 if (($this->textvar & TextVars::FC_KERNING) && $i > 0) { // mPDF 5.7.1
7905 $lastc = mb_substr($s, ($i - 1), 1, $this->mb_enc);
7906 $ulastc = $this->UTF8StringToArray($lastc, false);
7907 $uc = $this->UTF8StringToArray($c, false);
7908 if (isset($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]])) {
7909 $cw += ($this->CurrentFont['kerninfo'][$ulastc[0]][$uc[0]] * $this->FontSizePt / 1000 );
7910 }
7911 }
7912 }
7913
7914 if ($i == 0) {
7915 $cw += $lbw * Mpdf::SCALE;
7916 $contentB[(count($contentB) - 1)] .= 'L';
7917 }
7918 if ($i == ($clen - 1)) {
7919 $cw += $rbw * Mpdf::SCALE;
7920 $contentB[(count($contentB) - 1)] .= 'R';
7921 }
7922 if ($c == ' ') {
7923 $currContent .= $c;
7924 $contentWidth += $cw;
7925 continue;
7926 }
7927
7928 // Paragraph INDENT
7929 $WidthCorrection = 0;
7930 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && isset($this->blk[$this->blklvl]['text_indent']) && ($lineCount == 0) && (!$is_table) && ($align != 'C')) {
7931 $ti = $this->sizeConverter->convert($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4
7932 $WidthCorrection = ($ti * Mpdf::SCALE);
7933 }
7934 // OUTDENT
7935 foreach ($this->objectbuffer as $k => $objattr) { // mPDF 6 DOTTAB
7936 if ($objattr['type'] == 'dottab') {
7937 $WidthCorrection -= ($objattr['outdent'] * Mpdf::SCALE);
7938 break;
7939 }
7940 }
7941
7942
7943 // Added mPDF 3.0 Float DIV
7944 $fpaddingR = 0;
7945 $fpaddingL = 0;
7946 /* -- CSS-FLOAT -- */
7947 if (count($this->floatDivs)) {
7948 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
7949 if ($r_exists) {
7950 $fpaddingR = $r_width;
7951 }
7952 if ($l_exists) {
7953 $fpaddingL = $l_width;
7954 }
7955 }
7956 /* -- END CSS-FLOAT -- */
7957
7958 $usey = $this->y + 0.002;
7959 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 0)) {
7960 $usey += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
7961 }
7962
7963 /* -- CSS-IMAGE-FLOAT -- */
7964 // If float exists at this level
7965 if (isset($this->floatmargins['R']) && $usey <= $this->floatmargins['R']['y1'] && $usey >= $this->floatmargins['R']['y0'] && !$this->floatmargins['R']['skipline']) {
7966 $fpaddingR += $this->floatmargins['R']['w'];
7967 }
7968 if (isset($this->floatmargins['L']) && $usey <= $this->floatmargins['L']['y1'] && $usey >= $this->floatmargins['L']['y0'] && !$this->floatmargins['L']['skipline']) {
7969 $fpaddingL += $this->floatmargins['L']['w'];
7970 }
7971 /* -- END CSS-IMAGE-FLOAT -- */
7972
7973
7974 // try adding another char
7975 if (( $contentWidth + $cw > $maxWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) ) + 0.001)) {// 0.001 is to correct for deviations converting mm=>pts
7976 // it won't fit, output what we already have
7977 $lineCount++;
7978
7979 // contains any content that didn't make it into this print
7980 $savedContent = '';
7981 $savedContentB = '';
7982 $savedOTLdata = []; // mPDF 5.7.1
7983 $savedFont = [];
7984 $savedObj = [];
7985 $savedPreOTLdata = []; // mPDF 5.7.1
7986 $savedPreContent = [];
7987 $savedPreContentB = [];
7988 $savedPreFont = [];
7989
7990 // mPDF 6
7991 // New line-breaking algorithm
7993 // LINE BREAKING
7995 $breakfound = false;
7996 $contentctr = count($content) - 1;
7997 if ($this->usingCoreFont) {
7998 $charctr = strlen($currContent);
7999 } else {
8000 $charctr = mb_strlen($currContent, $this->mb_enc);
8001 }
8002 $checkchar = $c;
8003 $prevchar = $this->_getPrevChar($contentctr, $charctr, $content);
8004
8005 /* -- CJK-FONTS -- */
8006 // 1) CJK Overflowing a) punctuation or b) Oikomi
8007 // Next character ($c) is suitable to add as overhanging or squeezed punctuation, or Oikomi
8008 if ($CJKoverflow || $Oikomi) { // If flag already set
8009 $CJKoverflow = false;
8010 $Oikomi = false;
8011 $breakfound = true;
8012 }
8013 if (!$this->usingCoreFont && !$breakfound && $this->checkCJK) {
8014
8015 // Get next/following character (in this chunk)
8016 $followingchar = '';
8017 if ($i < ($clen - 1)) {
8018 if ($this->usingCoreFont) {
8019 $followingchar = $s[$i + 1];
8020 } else {
8021 $followingchar = mb_substr($s, $i + 1, 1, $this->mb_enc);
8022 }
8023 }
8024
8025 // 1a) Overflow punctuation
8026 if (preg_match("/[" . $this->pregCJKchars . "]/u", $prevchar) && preg_match("/[" . $this->CJKoverflow . "]/u", $checkchar) && $this->allowCJKorphans) {
8027 // add character onto this line
8028 $currContent .= $c;
8029 $contentWidth += $cw;
8030 $CJKoverflow = true; // Set flag
8031 continue;
8032 } elseif (preg_match("/[" . $this->pregCJKchars . "]/u", $checkchar) && $this->allowCJKorphans &&
8033 (preg_match("/[" . $this->CJKleading . "]/u", $followingchar) || preg_match("/[" . $this->CJKfollowing . "]/u", $checkchar)) &&
8034 !preg_match("/[" . $this->CJKleading . "]/u", $checkchar) && !preg_match("/[" . $this->CJKfollowing . "]/u", $followingchar) &&
8035 !(preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $followingchar) && preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $checkchar))) {
8036 // 1b) Try squeezing another character(s) onto this line = Oikomi, if character cannot end line
8037 // or next character cannot start line (and not splitting CJK numerals)
8038 // NB otherwise it move lastchar(s) to next line to keep $c company = Oidashi, which is done below in standard way
8039 // add character onto this line
8040 $currContent .= $c;
8041 $contentWidth += $cw;
8042 $Oikomi = true; // Set flag
8043 continue;
8044 }
8045 }
8046 /* -- END CJK-FONTS -- */
8047 /* -- HYPHENATION -- */
8048
8049 // AUTOMATIC HYPHENATION
8050 // 2) Automatic hyphen in current word (does not cross tags)
8051 if (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] == 1) {
8052 $currWord = '';
8053 // Look back and ahead to get current word
8054 for ($ac = $charctr - 1; $ac >= 0; $ac--) {
8055 if ($this->usingCoreFont) {
8056 $addc = substr($currContent, $ac, 1);
8057 } else {
8058 $addc = mb_substr($currContent, $ac, 1, $this->mb_enc);
8059 }
8060 if ($addc == ' ') {
8061 break;
8062 }
8063 $currWord = $addc . $currWord;
8064 }
8065 $start = $ac + 1;
8066 for ($ac = $i; $ac < ($clen - 1); $ac++) {
8067 if ($this->usingCoreFont) {
8068 $addc = substr($s, $ac, 1);
8069 } else {
8070 $addc = mb_substr($s, $ac, 1, $this->mb_enc);
8071 }
8072 if ($addc == ' ') {
8073 break;
8074 }
8075 $currWord .= $addc;
8076 }
8077 $ptr = $this->hyphenator->hyphenateWord($currWord, $charctr - $start);
8078 if ($ptr > -1) {
8079 $breakfound = [$contentctr, $start + $ptr, $contentctr, $start + $ptr, 'hyphen'];
8080 }
8081 }
8082 /* -- END HYPHENATION -- */
8083
8084 // Search backwards to find first line-break opportunity
8085 while ($breakfound == false && $prevchar !== false) {
8086 $cutcontentctr = $contentctr;
8087 $cutcharctr = $charctr;
8088 $prevchar = $this->_moveToPrevChar($contentctr, $charctr, $content);
8090 // 3) Break at SPACE
8092 if ($prevchar == ' ') {
8093 $breakfound = [$contentctr, $charctr, $cutcontentctr, $cutcharctr, 'discard'];
8094 }
8095 // 4) Break at U+200B in current word (Khmer, Lao & Thai Invisible word boundary, and Tibetan)
8097 elseif ($prevchar == "\xe2\x80\x8b") { // U+200B Zero-width Word Break
8098 $breakfound = [$contentctr, $charctr, $cutcontentctr, $cutcharctr, 'discard'];
8099 }
8100 // 5) Break at Hard HYPHEN '-' or U+2010
8102 elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && ($prevchar == '-' || $prevchar == "\xe2\x80\x90")) {
8103 // Don't break a URL
8104 // Look back to get first part of current word
8105 $checkw = '';
8106 for ($ac = $charctr - 1; $ac >= 0; $ac--) {
8107 if ($this->usingCoreFont) {
8108 $addc = substr($currContent, $ac, 1);
8109 } else {
8110 $addc = mb_substr($currContent, $ac, 1, $this->mb_enc);
8111 }
8112 if ($addc == ' ') {
8113 break;
8114 }
8115 $checkw = $addc . $checkw;
8116 }
8117 // Don't break if HyphenMinus AND (a URL or before a numeral or before a >)
8118 if ((!preg_match('/(http:|ftp:|https:|www\.)/', $checkw) && $checkchar != '>' && !preg_match('/[0-9]/', $checkchar)) || $prevchar == "\xe2\x80\x90") {
8119 $breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
8120 }
8121 }
8122 // 6) Break at Soft HYPHEN (replace with hard hyphen)
8124 elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && !$this->usingCoreFont && $prevchar == "\xc2\xad") {
8125 $breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
8126 $content[$contentctr] = mb_substr($content[$contentctr], 0, $charctr, $this->mb_enc) . '-' . mb_substr($content[$contentctr], $charctr + 1, mb_strlen($content[$contentctr]), $this->mb_enc);
8127 if (!empty($cOTLdata[$contentctr])) {
8128 $cOTLdata[$contentctr]['char_data'][$charctr] = ['bidi_class' => 9, 'uni' => 45];
8129 $cOTLdata[$contentctr]['group'][$charctr] = 'C';
8130 }
8131 } elseif (isset($this->textparam['hyphens']) && $this->textparam['hyphens'] != 2 && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats' && $prevchar == chr(173)) {
8132 $breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
8133 $content[$contentctr] = substr($content[$contentctr], 0, $charctr) . '-' . substr($content[$contentctr], $charctr + 1);
8134 } /* -- CJK-FONTS -- */
8136 // 7) Break at CJK characters (unless forbidden characters to end or start line)
8137 // CJK Avoiding line break in the middle of numerals
8139 elseif (!$this->usingCoreFont && $this->checkCJK && preg_match("/[" . $this->pregCJKchars . "]/u", $checkchar) &&
8140 !preg_match("/[" . $this->CJKfollowing . "]/u", $checkchar) && !preg_match("/[" . $this->CJKleading . "]/u", $prevchar) &&
8141 !(preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $prevchar) && preg_match("/[0-9\x{ff10}-\x{ff19}]/u", $checkchar))) {
8142 $breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
8143 }
8144 /* -- END CJK-FONTS -- */
8146 // 8) Break at OBJECT (Break before all objects here - selected objects are moved forward to next line below e.g. dottab)
8148 if (isset($this->objectbuffer[$contentctr])) {
8149 $breakfound = [$cutcontentctr, $cutcharctr, $cutcontentctr, $cutcharctr, 'cut'];
8150 }
8151
8152
8153 $checkchar = $prevchar;
8154 }
8155
8156 // If a line-break opportunity found:
8157 if (is_array($breakfound)) {
8158 $contentctr = $breakfound[0];
8159 $charctr = $breakfound[1];
8160 $cutcontentctr = $breakfound[2];
8161 $cutcharctr = $breakfound[3];
8162 $type = $breakfound[4];
8163 // Cache chunks which are already processed, but now need to be passed on to the new line
8164 for ($ix = count($content) - 1; $ix > $cutcontentctr; $ix--) {
8165 // save and crop off any subsequent chunks
8166 /* -- OTL -- */
8167 if (!empty($sOTLdata)) {
8168 $tmpOTL = array_pop($cOTLdata);
8169 $savedPreOTLdata[] = $tmpOTL;
8170 }
8171 /* -- END OTL -- */
8172 $savedPreContent[] = array_pop($content);
8173 $savedPreContentB[] = array_pop($contentB);
8174 $savedPreFont[] = array_pop($font);
8175 }
8176
8177 // Next cache the part which will start the next line
8178 if ($this->usingCoreFont) {
8179 $savedPreContent[] = substr($content[$cutcontentctr], $cutcharctr);
8180 } else {
8181 $savedPreContent[] = mb_substr($content[$cutcontentctr], $cutcharctr, mb_strlen($content[$cutcontentctr]), $this->mb_enc);
8182 }
8183 $savedPreContentB[] = preg_replace('/L/', '', $contentB[$cutcontentctr]);
8184 $savedPreFont[] = $font[$cutcontentctr];
8185 /* -- OTL -- */
8186 if (!empty($sOTLdata)) {
8187 $savedPreOTLdata[] = $this->otl->splitOTLdata($cOTLdata[$cutcontentctr], $cutcharctr, $cutcharctr);
8188 }
8189 /* -- END OTL -- */
8190
8191
8192 // Finally adjust the Current content which ends this line
8193 if ($cutcharctr == 0 && $type == 'discard') {
8194 array_pop($content);
8195 array_pop($contentB);
8196 array_pop($font);
8197 array_pop($cOTLdata);
8198 }
8199
8200 $currContent = & $content[count($content) - 1];
8201 if ($this->usingCoreFont) {
8202 $currContent = substr($currContent, 0, $charctr);
8203 } else {
8204 $currContent = mb_substr($currContent, 0, $charctr, $this->mb_enc);
8205 }
8206
8207 if (!empty($sOTLdata)) {
8208 $savedPreOTLdata[] = $this->otl->splitOTLdata($cOTLdata[(count($cOTLdata) - 1)], mb_strlen($currContent, $this->mb_enc));
8209 }
8210
8211 if (strpos($contentB[(count($contentB) - 1)], 'R') !== false) { // ???
8212 $contentB[count($content) - 1] = preg_replace('/R/', '', $contentB[count($content) - 1]); // ???
8213 }
8214
8215 if ($type == 'hyphen') {
8216 $currContent .= '-';
8217 if (!empty($cOTLdata[(count($cOTLdata) - 1)])) {
8218 $cOTLdata[(count($cOTLdata) - 1)]['char_data'][] = ['bidi_class' => 9, 'uni' => 45];
8219 $cOTLdata[(count($cOTLdata) - 1)]['group'] .= 'C';
8220 }
8221 }
8222
8223 $savedContent = '';
8224 $savedContentB = '';
8225 $savedFont = [];
8226 $savedOTLdata = [];
8227 }
8228 // If no line-break opportunity found - split at current position
8229 // or - Next character ($c) is suitable to add as overhanging or squeezed punctuation, or Oikomi, as set above by:
8230 // 1) CJK Overflowing a) punctuation or b) Oikomi
8231 // in which case $breakfound==1 and NOT array
8232
8233 if (!is_array($breakfound)) {
8234 $savedFont = $this->saveFont();
8235 if (!empty($sOTLdata)) {
8236 $savedOTLdata = $this->otl->splitOTLdata($cOTLdata[(count($cOTLdata) - 1)], mb_strlen($currContent, $this->mb_enc));
8237 }
8238 }
8239
8240 if ($content[count($content) - 1] == '' && !isset($this->objectbuffer[count($content) - 1])) {
8241 array_pop($content);
8242 array_pop($contentB);
8243 array_pop($font);
8244 array_pop($cOTLdata);
8245 $currContent = & $content[count($content) - 1];
8246 }
8247
8248 // Right Trim current content - including CJK space, and for OTLdata
8249 // incl. CJK - strip CJK space at end of line &#x3000; = \xe3\x80\x80 = CJK space
8250 $currContent = $currContent ? rtrim($currContent) : '';
8251 if ($this->checkCJK) {
8252 $currContent = preg_replace("/\xe3\x80\x80$/", '', $currContent);
8253 } // *CJK-FONTS*
8254 /* -- OTL -- */
8255 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
8256 $this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], false, true); // NB also does U+3000
8257 }
8258 /* -- END OTL -- */
8259
8260
8261 // Selected OBJECTS are moved forward to next line, unless they come before a space or U+200B (type='discard')
8262 if (isset($this->objectbuffer[(count($content) - 1)]) && (!isset($type) || $type != 'discard')) {
8263 $objtype = $this->objectbuffer[(count($content) - 1)]['type'];
8264 if ($objtype == 'dottab' || $objtype == 'bookmark' || $objtype == 'indexentry' || $objtype == 'toc' || $objtype == 'annot') {
8265 $savedObj = array_pop($this->objectbuffer);
8266 }
8267 }
8268
8269
8270 // Decimal alignment (cancel if wraps to > 1 line)
8271 if ($is_table && substr($align, 0, 1) == 'D') {
8272 $align = substr($align, 2, 1);
8273 }
8274
8275 $lineBox = [];
8276
8277 $this->_setInlineBlockHeights($lineBox, $stackHeight, $content, $font, $is_table);
8278
8279 // update $contentWidth since it has changed with cropping
8280 $contentWidth = 0;
8281
8282 $inclCursive = false;
8283 foreach ($content as $k => $chunk) {
8284 if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
8285 // LIST MARKERS
8286 if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker']) {
8287 if ($this->objectbuffer[$k]['listmarkerposition'] != 'outside') {
8288 $contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * Mpdf::SCALE;
8289 }
8290 } else {
8291 $contentWidth += $this->objectbuffer[$k]['OUTER-WIDTH'] * Mpdf::SCALE;
8292 }
8293 } elseif (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
8294 $this->restoreFont($font[$k], false);
8295 if ($this->checkCJK && $k == count($content) - 1 && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $this->CJKforceend) {
8296 // force-end overhang
8297 $hanger = mb_substr($chunk, mb_strlen($chunk, $this->mb_enc) - 1, 1, $this->mb_enc);
8298 // Probably ought to do something with char_data and GPOS in cOTLdata...
8299 $content[$k] = $chunk = mb_substr($chunk, 0, mb_strlen($chunk, $this->mb_enc) - 1, $this->mb_enc);
8300 }
8301
8302 // Soft Hyphens chr(173) + Replace NBSP with SPACE + Set inclcursive if includes CURSIVE TEXT
8303 if (!$this->usingCoreFont) {
8304 /* -- OTL -- */
8305 if ((isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) || !empty($sOTLdata)) {
8306 $this->otl->removeChar($chunk, $cOTLdata[$k], "\xc2\xad");
8307 $this->otl->replaceSpace($chunk, $cOTLdata[$k]); // NBSP -> space
8308 if (preg_match("/([" . $this->pregCURSchars . "])/u", $chunk)) {
8309 $inclCursive = true;
8310 }
8311 $content[$k] = $chunk;
8312 } /* -- END OTL -- */ else { // *OTL*
8313 $content[$k] = $chunk = str_replace("\xc2\xad", '', $chunk);
8314 $content[$k] = $chunk = str_replace(chr(194) . chr(160), chr(32), $chunk);
8315 } // *OTL*
8316 } elseif ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
8317 $content[$k] = $chunk = str_replace(chr(173), '', $chunk);
8318 $content[$k] = $chunk = str_replace(chr(160), chr(32), $chunk);
8319 }
8320
8321 $contentWidth += $this->GetStringWidth($chunk, true, (isset($cOTLdata[$k]) ? $cOTLdata[$k] : false), $this->textvar) * Mpdf::SCALE; // mPDF 5.7.1
8322 if (!empty($this->spanborddet)) {
8323 if (isset($this->spanborddet['L']['w']) && strpos($contentB[$k], 'L') !== false) {
8324 $contentWidth += $this->spanborddet['L']['w'] * Mpdf::SCALE;
8325 }
8326 if (isset($this->spanborddet['R']['w']) && strpos($contentB[$k], 'R') !== false) {
8327 $contentWidth += $this->spanborddet['R']['w'] * Mpdf::SCALE;
8328 }
8329 }
8330 }
8331 }
8332
8333 $lastfontreqstyle = (isset($font[count($font) - 1]['ReqFontStyle']) ? $font[count($font) - 1]['ReqFontStyle'] : '');
8334 $lastfontstyle = (isset($font[count($font) - 1]['style']) ? $font[count($font) - 1]['style'] : '');
8335 if ($blockdir == 'ltr' && strpos($lastfontreqstyle, "I") !== false && strpos($lastfontstyle, "I") === false) { // Artificial italic
8336 $lastitalic = $this->FontSize * 0.15 * Mpdf::SCALE;
8337 } else {
8338 $lastitalic = 0;
8339 }
8340
8341
8342
8343
8344 // NOW FORMAT THE LINE TO OUTPUT
8345 if (!$table_draft) {
8346 // DIRECTIONALITY RTL
8347 $chunkorder = range(0, count($content) - 1); // mPDF 5.7
8348 /* -- OTL -- */
8349 // mPDF 6
8350 if ($blockdir == 'rtl' || $this->biDirectional) {
8351 $this->otl->bidiReorder($chunkorder, $content, $cOTLdata, $blockdir);
8352 // From this point on, $content and $cOTLdata may contain more elements (and re-ordered) compared to
8353 // $this->objectbuffer and $font ($chunkorder contains the mapping)
8354 }
8355
8356 /* -- END OTL -- */
8357 // Remove any XAdvance from OTL data at end of line
8358 foreach ($chunkorder as $aord => $k) {
8359 if (count($cOTLdata)) {
8360 $this->restoreFont($font[$k], false);
8361 // ...WriteFlowingBlock...
8362 if ($aord == count($chunkorder) - 1 && isset($cOTLdata[$aord]['group'])) { // Last chunk on line
8363 $nGPOS = strlen($cOTLdata[$aord]['group']) - 1; // Last character
8364 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL']) || isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'])) {
8365 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'])) {
8366 $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] * 1000 / $this->CurrentFont['unitsPerEm'];
8367 } else {
8368 $w = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] * 1000 / $this->CurrentFont['unitsPerEm'];
8369 }
8370 $w *= ($this->FontSize / 1000);
8371 $contentWidth -= $w * Mpdf::SCALE;
8372 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = 0;
8373 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = 0;
8374 }
8375
8376 // If last character has an XPlacement set, adjust width calculation, and add to XAdvance to account for it
8377 if (isset($cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'])) {
8378 $w = -$cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'] * 1000 / $this->CurrentFont['unitsPerEm'];
8379 $w *= ($this->FontSize / 1000);
8380 $contentWidth -= $w * Mpdf::SCALE;
8381 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceL'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
8382 $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XAdvanceR'] = $cOTLdata[$aord]['GPOSinfo'][$nGPOS]['XPlacement'];
8383 }
8384 }
8385 }
8386 }
8387
8388 // JUSTIFICATION J
8389 $jcharspacing = 0;
8390 $jws = 0;
8391 $nb_carac = 0;
8392 $nb_spaces = 0;
8393 $jkashida = 0;
8394 // if it's justified, we need to find the char/word spacing (or if hanger $this->CJKforceend)
8395 if (($align == 'J' && !$CJKoverflow) || (($contentWidth + $lastitalic > $maxWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) ) + 0.001) && (!$CJKoverflow || ($CJKoverflow && !$this->allowCJKoverflow))) || $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) { // 0.001 is to correct for deviations converting mm=>pts
8396 // JUSTIFY J (Use character spacing)
8397 // WORD SPACING
8398 // mPDF 5.7
8399 foreach ($chunkorder as $aord => $k) {
8400 $chunk = isset($content[$aord]) ? $content[$aord] : '';
8401 if (!isset($this->objectbuffer[$k]) || (isset($this->objectbuffer[$k]) && !$this->objectbuffer[$k])) {
8402 $nb_carac += mb_strlen($chunk, $this->mb_enc);
8403 $nb_spaces += mb_substr_count($chunk, ' ', $this->mb_enc);
8404 // Use GPOS OTL
8405 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
8406 if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
8407 $nb_carac -= substr_count($cOTLdata[$aord]['group'], 'M');
8408 }
8409 }
8410 } else {
8411 $nb_carac ++;
8412 } // mPDF 6 allow spacing for inline object
8413 }
8414 // GetJSpacing adds kashida spacing to GPOSinfo if appropriate for Font
8415 list($jcharspacing, $jws, $jkashida) = $this->GetJspacing($nb_carac, $nb_spaces, ($maxWidth - $lastitalic - $contentWidth - $WidthCorrection - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) )), $inclCursive, $cOTLdata);
8416 }
8417
8418 // WORD SPACING
8419 $empty = $maxWidth - $lastitalic - $WidthCorrection - $contentWidth - (($this->cMarginL + $this->cMarginR) * Mpdf::SCALE) - ($paddingL + $paddingR + (($fpaddingL + $fpaddingR) * Mpdf::SCALE) );
8420
8421 $empty -= ($jcharspacing * ($nb_carac - 1)); // mPDF 6 nb_carac MINUS 1
8422 $empty -= ($jws * $nb_spaces);
8423 $empty -= ($jkashida);
8424 $empty /= Mpdf::SCALE;
8425
8426 $b = ''; // do not use borders
8427 // Get PAGEBREAK TO TEST for height including the top border/padding
8428 $check_h = max($this->divheight, $stackHeight);
8429 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($this->blklvl > 0) && ($lineCount == 1) && (!$is_table)) {
8430 $check_h += ($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['border_top']['w']);
8431 }
8432
8433 if ($this->ColActive && $check_h > ($this->PageBreakTrigger - $this->y0)) {
8434 $this->SetCol($this->NbCol - 1);
8435 }
8436
8437 // PAGEBREAK
8438 // 'If' below used in order to fix "first-line of other page with justify on" bug
8439 if (!$is_table && ($this->y + $check_h) > $this->PageBreakTrigger and ! $this->InFooter and $this->AcceptPageBreak()) {
8440 $bak_x = $this->x; // Current X position
8441 // WORD SPACING
8442 $ws = $this->ws; // Word Spacing
8443 $charspacing = $this->charspacing; // Character Spacing
8444 $this->ResetSpacing();
8445
8446 $this->AddPage($this->CurOrientation);
8447
8448 $this->x = $bak_x;
8449 // Added to correct for OddEven Margins
8450 $currentx += $this->MarginCorrection;
8451 $this->x += $this->MarginCorrection;
8452
8453 // WORD SPACING
8454 $this->SetSpacing($charspacing, $ws);
8455 }
8456
8457 if ($this->kwt && !$is_table) { // mPDF 5.7+
8458 $this->printkwtbuffer();
8459 $this->kwt = false;
8460 }
8461
8462
8463 /* -- COLUMNS -- */
8464 // COLS
8465 // COLUMN CHANGE
8466 if ($this->CurrCol != $oldcolumn) {
8467 $currentx += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
8468 $this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
8469 $oldcolumn = $this->CurrCol;
8470 }
8471
8472 if ($this->ColActive && !$is_table) {
8473 $this->breakpoints[$this->CurrCol][] = $this->y;
8474 } // *COLUMNS*
8475 /* -- END COLUMNS -- */
8476
8477 // TOP MARGIN
8478 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($this->blk[$this->blklvl]['margin_top']) && ($lineCount == 1) && (!$is_table)) {
8479 $this->DivLn($this->blk[$this->blklvl]['margin_top'], $this->blklvl - 1, true, $this->blk[$this->blklvl]['margin_collapse']);
8480 if ($this->ColActive) {
8481 $this->breakpoints[$this->CurrCol][] = $this->y;
8482 } // *COLUMNS*
8483 }
8484
8485
8486 // Update y0 for top of block (used to paint border)
8487 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 1) && (!$is_table)) {
8488 $this->blk[$this->blklvl]['y0'] = $this->y;
8489 $this->blk[$this->blklvl]['startpage'] = $this->page;
8490 if ($this->blk[$this->blklvl]['float']) {
8491 $this->blk[$this->blklvl]['float_start_y'] = $this->y;
8492 }
8493 }
8494
8495 // TOP PADDING and BORDER spacing/fill
8496 if (($newblock) && ($blockstate == 1 || $blockstate == 3) && (($this->blk[$this->blklvl]['padding_top']) || ($this->blk[$this->blklvl]['border_top'])) && ($lineCount == 1) && (!$is_table)) {
8497 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
8498 $this->DivLn($this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'], -3, true, false, 1);
8499 if ($this->ColActive) {
8500 $this->breakpoints[$this->CurrCol][] = $this->y;
8501 } // *COLUMNS*
8502 }
8503
8504 $arraysize = count($chunkorder);
8505
8506 $margins = ($this->cMarginL + $this->cMarginR) + ($ipaddingL + $ipaddingR + $fpaddingR + $fpaddingR );
8507
8508 // PAINT BACKGROUND FOR THIS LINE
8509 if (!$is_table) {
8510 $this->DivLn($stackHeight, $this->blklvl, false);
8511 } // false -> don't advance y
8512
8513 $this->x = $currentx + $this->cMarginL + $ipaddingL + $fpaddingL;
8514 if ($align == 'R') {
8515 $this->x += $empty;
8516 } elseif ($align == 'C') {
8517 $this->x += ($empty / 2);
8518 }
8519
8520 // Paragraph INDENT
8521 if (isset($this->blk[$this->blklvl]['text_indent']) && ($newblock) && ($blockstate == 1 || $blockstate == 3) && ($lineCount == 1) && (!$is_table) && ($blockdir != 'rtl') && ($align != 'C')) {
8522 $ti = $this->sizeConverter->convert($this->blk[$this->blklvl]['text_indent'], $this->blk[$this->blklvl]['inner_width'], $this->blk[$this->blklvl]['InlineProperties']['size'], false); // mPDF 5.7.4
8523 $this->x += $ti;
8524 }
8525
8526 // BIDI magic_reverse moved upwards from here
8527 foreach ($chunkorder as $aord => $k) { // mPDF 5.7
8528
8529 $chunk = isset($content[$aord]) ? $content[$aord] : '';
8530
8531 if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]) {
8532 $xadj = $this->x - $this->objectbuffer[$k]['OUTER-X'];
8533 $this->objectbuffer[$k]['OUTER-X'] += $xadj;
8534 $this->objectbuffer[$k]['BORDER-X'] += $xadj;
8535 $this->objectbuffer[$k]['INNER-X'] += $xadj;
8536
8537 if ($this->objectbuffer[$k]['type'] == 'listmarker') {
8538 $this->objectbuffer[$k]['lineBox'] = $lineBox[-1]; // Block element details for glyph-origin
8539 }
8540 $yadj = $this->y - $this->objectbuffer[$k]['OUTER-Y'];
8541 if ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
8542 $this->objectbuffer[$k]['lineBox'] = $lineBox[$k]; // element details for glyph-origin
8543 }
8544 if ($this->objectbuffer[$k]['type'] != 'dottab') { // mPDF 6 DOTTAB
8545 $yadj += $lineBox[$k]['top'];
8546 }
8547 $this->objectbuffer[$k]['OUTER-Y'] += $yadj;
8548 $this->objectbuffer[$k]['BORDER-Y'] += $yadj;
8549 $this->objectbuffer[$k]['INNER-Y'] += $yadj;
8550 }
8551
8552 $this->restoreFont($font[$k]); // mPDF 5.7
8553
8554 $this->SetSpacing(($this->fixedlSpacing * Mpdf::SCALE) + $jcharspacing, ($this->fixedlSpacing + $this->minwSpacing) * Mpdf::SCALE + $jws);
8555 // Now unset these values so they don't influence GetStringwidth below or in fn. Cell
8556 $this->fixedlSpacing = false;
8557 $this->minwSpacing = 0;
8558
8559 $save_vis = $this->visibility;
8560 if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->textparam['visibility'] != $this->visibility) {
8561 $this->SetVisibility($this->textparam['visibility']);
8562 }
8563 // *********** SPAN BACKGROUND COLOR ***************** //
8564 if ($this->spanbgcolor) {
8565 $cor = $this->spanbgcolorarray;
8566 $this->SetFColor($cor);
8567 $save_fill = $fill;
8568 $spanfill = 1;
8569 $fill = 1;
8570 }
8571 if (!empty($this->spanborddet)) {
8572 if (strpos($contentB[$k], 'L') !== false) {
8573 $this->x += (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
8574 }
8575 if (strpos($contentB[$k], 'L') === false) {
8576 $this->spanborddet['L']['s'] = $this->spanborddet['L']['w'] = 0;
8577 }
8578 if (strpos($contentB[$k], 'R') === false) {
8579 $this->spanborddet['R']['s'] = $this->spanborddet['R']['w'] = 0;
8580 }
8581 }
8582
8583 // WORD SPACING
8584 // StringWidth this time includes any kashida spacing
8585 $stringWidth = $this->GetStringWidth($chunk, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, true);
8586
8587 $nch = mb_strlen($chunk, $this->mb_enc);
8588 // Use GPOS OTL
8589 if (isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0xFF)) {
8590 if (isset($cOTLdata[$aord]['group']) && $cOTLdata[$aord]['group']) {
8591 $nch -= substr_count($cOTLdata[$aord]['group'], 'M');
8592 }
8593 }
8594 $stringWidth += ( $this->charspacing * $nch / Mpdf::SCALE );
8595
8596 $stringWidth += ( $this->ws * mb_substr_count($chunk, ' ', $this->mb_enc) / Mpdf::SCALE );
8597
8598 if (isset($this->objectbuffer[$k])) {
8599 // LIST MARKERS // mPDF 6 Lists
8600 if ($this->objectbuffer[$k]['type'] == 'image' && isset($this->objectbuffer[$k]['listmarker']) && $this->objectbuffer[$k]['listmarker'] && $this->objectbuffer[$k]['listmarkerposition'] == 'outside') {
8601 $stringWidth = 0;
8602 } else {
8603 $stringWidth = $this->objectbuffer[$k]['OUTER-WIDTH'];
8604 }
8605 }
8606
8607 if ($stringWidth == 0) {
8608 $stringWidth = 0.000001;
8609 }
8610
8611 if ($aord == $arraysize - 1) {
8612 $stringWidth -= ( $this->charspacing / Mpdf::SCALE );
8613 if ($this->checkCJK && $CJKoverflow && $align == 'J' && $this->allowCJKoverflow && $hanger && $this->CJKforceend) {
8614 // force-end overhang
8615 $this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false));
8616 $this->Cell($this->GetStringWidth($hanger), $stackHeight, $hanger, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false));
8617 } else {
8618 $this->Cell($stringWidth, $stackHeight, $chunk, '', 1, '', $fill, $this->HREF, $currentx, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // mono-style line or last part (skips line)
8619 }
8620 } else {
8621 $this->Cell($stringWidth, $stackHeight, $chunk, '', 0, '', $fill, $this->HREF, 0, 0, 0, 'M', $fill, true, (isset($cOTLdata[$aord]) ? $cOTLdata[$aord] : false), $this->textvar, (isset($lineBox[$k]) ? $lineBox[$k] : false)); // first or middle part
8622 }
8623
8624 if (!empty($this->spanborddet)) {
8625 if (strpos($contentB[$k], 'R') !== false && $aord != $arraysize - 1) {
8626 $this->x += $this->spanborddet['R']['w'];
8627 }
8628 }
8629 // *********** SPAN BACKGROUND COLOR OFF - RESET BLOCK BGCOLOR ***************** //
8630 if (isset($spanfill) && $spanfill) {
8631 $fill = $save_fill;
8632 $spanfill = 0;
8633 if ($fill) {
8634 $this->SetFColor($bcor);
8635 }
8636 }
8637 if (isset($this->textparam['visibility']) && $this->textparam['visibility'] && $this->visibility != $save_vis) {
8638 $this->SetVisibility($save_vis);
8639 }
8640 }
8641 } elseif ($table_draft) {
8642 $this->y += $stackHeight;
8643 }
8644
8645 if (!$is_table) {
8646 $this->maxPosR = max($this->maxPosR, ($this->w - $this->rMargin - $this->blk[$this->blklvl]['outer_right_margin']));
8647 $this->maxPosL = min($this->maxPosL, ($this->lMargin + $this->blk[$this->blklvl]['outer_left_margin']));
8648 }
8649
8650 // move on to the next line, reset variables, tack on saved content and current char
8651
8652 if (!$table_draft) {
8653 $this->printobjectbuffer($is_table, $blockdir);
8654 }
8655 $this->objectbuffer = [];
8656
8657
8658 /* -- CSS-IMAGE-FLOAT -- */
8659 // Update values if set to skipline
8660 if ($this->floatmargins) {
8661 $this->_advanceFloatMargins();
8662 }
8663 /* -- END CSS-IMAGE-FLOAT -- */
8664
8665 // Reset lineheight
8666 $stackHeight = $this->divheight;
8667 $valign = 'M';
8668
8669 $font = [];
8670 $content = [];
8671 $contentB = [];
8672 $cOTLdata = []; // mPDF 5.7.1
8673 $contentWidth = 0;
8674 if (!empty($savedObj)) {
8675 $this->objectbuffer[] = $savedObj;
8676 $font[] = $savedFont;
8677 $content[] = '';
8678 $contentB[] = '';
8679 $cOTLdata[] = []; // mPDF 5.7.1
8680 $contentWidth += $savedObj['OUTER-WIDTH'] * Mpdf::SCALE;
8681 }
8682 if (count($savedPreContent) > 0) {
8683 for ($ix = count($savedPreContent) - 1; $ix >= 0; $ix--) {
8684 $font[] = $savedPreFont[$ix];
8685 $content[] = $savedPreContent[$ix];
8686 $contentB[] = $savedPreContentB[$ix];
8687 if (!empty($sOTLdata)) {
8688 $cOTLdata[] = $savedPreOTLdata[$ix];
8689 }
8690 $this->restoreFont($savedPreFont[$ix]);
8691 $lbw = $rbw = 0; // Border widths
8692 if (!empty($this->spanborddet)) {
8693 $lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
8694 $rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
8695 }
8696 if ($ix > 0) {
8697 $contentWidth += $this->GetStringWidth($savedPreContent[$ix], true, (isset($savedPreOTLdata[$ix]) ? $savedPreOTLdata[$ix] : false), $this->textvar) * Mpdf::SCALE; // mPDF 5.7.1
8698 if (strpos($savedPreContentB[$ix], 'L') !== false) {
8699 $contentWidth += $lbw;
8700 }
8701 if (strpos($savedPreContentB[$ix], 'R') !== false) {
8702 $contentWidth += $rbw;
8703 }
8704 }
8705 }
8706 $savedPreContent = [];
8707 $savedPreContentB = [];
8708 $savedPreOTLdata = []; // mPDF 5.7.1
8709 $savedPreFont = [];
8710 $content[(count($content) - 1)] .= $c;
8711 } else {
8712 $font[] = $savedFont;
8713 $content[] = $savedContent . $c;
8714 $contentB[] = $savedContentB;
8715 $cOTLdata[] = $savedOTLdata; // mPDF 5.7.1
8716 }
8717
8718 $currContent = & $content[(count($content) - 1)];
8719 $this->restoreFont($font[(count($font) - 1)]); // mPDF 6.0
8720
8721 /* -- CJK-FONTS -- */
8722 // CJK - strip CJK space at start of line
8723 // &#x3000; = \xe3\x80\x80 = CJK space
8724 if ($this->checkCJK && $currContent == "\xe3\x80\x80") {
8725 $currContent = '';
8726 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
8727 $this->otl->trimOTLdata($cOTLdata[count($cOTLdata) - 1], true, false); // left trim U+3000
8728 }
8729 }
8730 /* -- END CJK-FONTS -- */
8731
8732 $lbw = $rbw = 0; // Border widths
8733 if (!empty($this->spanborddet)) {
8734 $lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
8735 $rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
8736 }
8737
8738 $contentWidth += $this->GetStringWidth($currContent, false, (isset($cOTLdata[(count($cOTLdata) - 1)]) ? $cOTLdata[(count($cOTLdata) - 1)] : false), $this->textvar) * Mpdf::SCALE; // mPDF 5.7.1
8739 if (strpos($savedContentB, 'L') !== false) {
8740 $contentWidth += $lbw;
8741 }
8742 $CJKoverflow = false;
8743 $hanger = '';
8744 } // another character will fit, so add it on
8745 else {
8746 $contentWidth += $cw;
8747 $currContent .= $c;
8748 }
8749 }
8750
8751 unset($content);
8752 unset($contentB);
8753 }
8754
8755 // ----------------------END OF FLOWING BLOCK------------------------------------//
8756
8757
8758 /* -- CSS-IMAGE-FLOAT -- */
8759 // Update values if set to skipline
8761 {
8762 // Update floatmargins - L
8763 if (isset($this->floatmargins['L']) && $this->floatmargins['L']['skipline'] && $this->floatmargins['L']['y0'] != $this->y) {
8764 $yadj = $this->y - $this->floatmargins['L']['y0'];
8765 $this->floatmargins['L']['y0'] = $this->y;
8766 $this->floatmargins['L']['y1'] += $yadj;
8767
8768 // Update objattr in floatbuffer
8769 if ($this->floatbuffer[$this->floatmargins['L']['id']]['border_left']['w']) {
8770 $this->floatbuffer[$this->floatmargins['L']['id']]['BORDER-Y'] += $yadj;
8771 }
8772 $this->floatbuffer[$this->floatmargins['L']['id']]['INNER-Y'] += $yadj;
8773 $this->floatbuffer[$this->floatmargins['L']['id']]['OUTER-Y'] += $yadj;
8774
8775 // Unset values
8776 $this->floatbuffer[$this->floatmargins['L']['id']]['skipline'] = false;
8777 $this->floatmargins['L']['skipline'] = false;
8778 $this->floatmargins['L']['id'] = '';
8779 }
8780 // Update floatmargins - R
8781 if (isset($this->floatmargins['R']) && $this->floatmargins['R']['skipline'] && $this->floatmargins['R']['y0'] != $this->y) {
8782 $yadj = $this->y - $this->floatmargins['R']['y0'];
8783 $this->floatmargins['R']['y0'] = $this->y;
8784 $this->floatmargins['R']['y1'] += $yadj;
8785
8786 // Update objattr in floatbuffer
8787 if ($this->floatbuffer[$this->floatmargins['R']['id']]['border_left']['w']) {
8788 $this->floatbuffer[$this->floatmargins['R']['id']]['BORDER-Y'] += $yadj;
8789 }
8790 $this->floatbuffer[$this->floatmargins['R']['id']]['INNER-Y'] += $yadj;
8791 $this->floatbuffer[$this->floatmargins['R']['id']]['OUTER-Y'] += $yadj;
8792
8793 // Unset values
8794 $this->floatbuffer[$this->floatmargins['R']['id']]['skipline'] = false;
8795 $this->floatmargins['R']['skipline'] = false;
8796 $this->floatmargins['R']['id'] = '';
8797 }
8798 }
8799
8800 /* -- END CSS-IMAGE-FLOAT -- */
8801
8802
8803
8804 /* -- END HTML-CSS -- */
8805
8806 function _SetTextRendering($mode)
8807 {
8808 if (!(($mode == 0) || ($mode == 1) || ($mode == 2))) {
8809 throw new \Mpdf\MpdfException("Text rendering mode should be 0, 1 or 2 (value : $mode)");
8810 }
8811 $tr = ($mode . ' Tr');
8812 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
8813 $this->writer->write($tr);
8814 }
8815 $this->pageoutput[$this->page]['TextRendering'] = $tr;
8816 }
8817
8819 {
8820 if (isset($params['outline-s']) && $params['outline-s']) {
8821 $this->SetLineWidth($params['outline-WIDTH']);
8822 $this->SetDColor($params['outline-COLOR']);
8823 $tr = ('2 Tr');
8824 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
8825 $this->writer->write($tr);
8826 }
8827 $this->pageoutput[$this->page]['TextRendering'] = $tr;
8828 } else { // Now resets all values
8829 $this->SetLineWidth(0.2);
8830 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
8831 $this->_SetTextRendering(0);
8832 $tr = ('0 Tr');
8833 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['TextRendering']) && $this->pageoutput[$this->page]['TextRendering'] != $tr) || !isset($this->pageoutput[$this->page]['TextRendering']))) {
8834 $this->writer->write($tr);
8835 }
8836 $this->pageoutput[$this->page]['TextRendering'] = $tr;
8837 }
8838 }
8839
8840 function Image($file, $x, $y, $w = 0, $h = 0, $type = '', $link = '', $paint = true, $constrain = true, $watermark = false, $shownoimg = true, $allowvector = true)
8841 {
8842 $orig_srcpath = $file;
8843 $this->GetFullPath($file);
8844
8845 $info = $this->imageProcessor->getImage($file, true, $allowvector, $orig_srcpath);
8846 if (!$info && $paint) {
8847 $info = $this->imageProcessor->getImage($this->noImageFile);
8848 if ($info) {
8849 $file = $this->noImageFile;
8850 $w = ($info['w'] * (25.4 / $this->img_dpi)); // 14 x 16px
8851 $h = ($info['h'] * (25.4 / $this->img_dpi)); // 14 x 16px
8852 }
8853 }
8854 if (!$info) {
8855 return false;
8856 }
8857 // Automatic width and height calculation if needed
8858 if ($w == 0 and $h == 0) {
8859 /* -- IMAGES-WMF -- */
8860 if ($info['type'] == 'wmf') {
8861 // WMF units are twips (1/20pt)
8862 // divide by 20 to get points
8863 // divide by k to get user units
8864 $w = abs($info['w']) / (20 * Mpdf::SCALE);
8865 $h = abs($info['h']) / (20 * Mpdf::SCALE);
8866 } else { /* -- END IMAGES-WMF -- */
8867 if ($info['type'] == 'svg') {
8868 // returned SVG units are pts
8869 // divide by k to get user units (mm)
8870 $w = abs($info['w']) / Mpdf::SCALE;
8871 $h = abs($info['h']) / Mpdf::SCALE;
8872 } else {
8873 // Put image at default image dpi
8874 $w = ($info['w'] / Mpdf::SCALE) * (72 / $this->img_dpi);
8875 $h = ($info['h'] / Mpdf::SCALE) * (72 / $this->img_dpi);
8876 }
8877 }
8878 }
8879 if ($w == 0) {
8880 $w = abs($h * $info['w'] / $info['h']);
8881 }
8882 if ($h == 0) {
8883 $h = abs($w * $info['h'] / $info['w']);
8884 }
8885
8886 /* -- WATERMARK -- */
8887 if ($watermark) {
8888 $maxw = $this->w;
8889 $maxh = $this->h;
8890 // Size = D PF or array
8891 if (is_array($this->watermark_size)) {
8892 $w = $this->watermark_size[0];
8893 $h = $this->watermark_size[1];
8894 } elseif (!is_string($this->watermark_size)) {
8895 $maxw -= $this->watermark_size * 2;
8896 $maxh -= $this->watermark_size * 2;
8897 $w = $maxw;
8898 $h = abs($w * $info['h'] / $info['w']);
8899 if ($h > $maxh) {
8900 $h = $maxh;
8901 $w = abs($h * $info['w'] / $info['h']);
8902 }
8903 } elseif ($this->watermark_size == 'F') {
8904 if ($this->ColActive) {
8905 $maxw = $this->w - ($this->DeflMargin + $this->DefrMargin);
8906 } else {
8907 $maxw = $this->pgwidth;
8908 }
8909 $maxh = $this->h - ($this->tMargin + $this->bMargin);
8910 $w = $maxw;
8911 $h = abs($w * $info['h'] / $info['w']);
8912 if ($h > $maxh) {
8913 $h = $maxh;
8914 $w = abs($h * $info['w'] / $info['h']);
8915 }
8916 } elseif ($this->watermark_size == 'P') { // Default P
8917 $w = $maxw;
8918 $h = abs($w * $info['h'] / $info['w']);
8919 if ($h > $maxh) {
8920 $h = $maxh;
8921 $w = abs($h * $info['w'] / $info['h']);
8922 }
8923 }
8924 // Automatically resize to maximum dimensions of page if too large
8925 if ($w > $maxw) {
8926 $w = $maxw;
8927 $h = abs($w * $info['h'] / $info['w']);
8928 }
8929 if ($h > $maxh) {
8930 $h = $maxh;
8931 $w = abs($h * $info['w'] / $info['h']);
8932 }
8933 // Position
8934 if (is_array($this->watermark_pos)) {
8935 $x = $this->watermark_pos[0];
8936 $y = $this->watermark_pos[1];
8937 } elseif ($this->watermark_pos == 'F') { // centred on printable area
8938 if ($this->ColActive) { // *COLUMNS*
8939 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) {
8940 $xadj = $this->DeflMargin - $this->DefrMargin;
8941 } // *COLUMNS*
8942 else {
8943 $xadj = 0;
8944 } // *COLUMNS*
8945 $x = ($this->DeflMargin - $xadj + ($this->w - ($this->DeflMargin + $this->DefrMargin)) / 2) - ($w / 2); // *COLUMNS*
8946 } // *COLUMNS*
8947 else { // *COLUMNS*
8948 $x = ($this->lMargin + ($this->pgwidth) / 2) - ($w / 2);
8949 } // *COLUMNS*
8950 $y = ($this->tMargin + ($this->h - ($this->tMargin + $this->bMargin)) / 2) - ($h / 2);
8951 } else { // default P - centred on whole page
8952 $x = ($this->w / 2) - ($w / 2);
8953 $y = ($this->h / 2) - ($h / 2);
8954 }
8955 /* -- IMAGES-WMF -- */
8956 if ($info['type'] == 'wmf') {
8957 $sx = $w * Mpdf::SCALE / $info['w'];
8958 $sy = -$h * Mpdf::SCALE / $info['h'];
8959 $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * Mpdf::SCALE - $sx * $info['x'], (($this->h - $y) * Mpdf::SCALE) - $sy * $info['y'], $info['i']);
8960 } else { /* -- END IMAGES-WMF -- */
8961 if ($info['type'] == 'svg') {
8962 $sx = $w * Mpdf::SCALE / $info['w'];
8963 $sy = -$h * Mpdf::SCALE / $info['h'];
8964 $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * Mpdf::SCALE - $sx * $info['x'], (($this->h - $y) * Mpdf::SCALE) - $sy * $info['y'], $info['i']);
8965 } else {
8966 $outstring = sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $w * Mpdf::SCALE, $h * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($y + $h)) * Mpdf::SCALE, $info['i']);
8967 }
8968 }
8969
8970 if ($this->watermarkImgBehind) {
8971 $outstring = $this->watermarkImgAlpha . "\n" . $outstring . "\n" . $this->SetAlpha(1, 'Normal', true) . "\n";
8972 $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', "\n" . $outstring . "\n" . '\\1', $this->pages[$this->page]);
8973 } else {
8974 $this->writer->write($outstring);
8975 }
8976
8977 return 0;
8978 } // end of IF watermark
8979 /* -- END WATERMARK -- */
8980
8981 if ($constrain) {
8982 // Automatically resize to maximum dimensions of page if too large
8983 if (isset($this->blk[$this->blklvl]['inner_width']) && $this->blk[$this->blklvl]['inner_width']) {
8984 $maxw = $this->blk[$this->blklvl]['inner_width'];
8985 } else {
8986 $maxw = $this->pgwidth;
8987 }
8988 if ($w > $maxw) {
8989 $w = $maxw;
8990 $h = abs($w * $info['h'] / $info['w']);
8991 }
8992 if ($h > $this->h - ($this->tMargin + $this->bMargin + 1)) { // see below - +10 to avoid drawing too close to border of page
8993 $h = $this->h - ($this->tMargin + $this->bMargin + 1);
8994 if ($this->fullImageHeight) {
8995 $h = $this->fullImageHeight;
8996 }
8997 $w = abs($h * $info['w'] / $info['h']);
8998 }
8999
9000
9001 // Avoid drawing out of the paper(exceeding width limits).
9002 // if ( ($x + $w) > $this->fw ) {
9003 if (($x + $w) > $this->w) {
9004 $x = $this->lMargin;
9005 $y += 5;
9006 }
9007
9008 $changedpage = false;
9009 $oldcolumn = $this->CurrCol;
9010 // Avoid drawing out of the page.
9011 if ($y + $h > $this->PageBreakTrigger and ! $this->InFooter and $this->AcceptPageBreak()) {
9012 $this->AddPage($this->CurOrientation);
9013 // Added to correct for OddEven Margins
9014 $x = $x + $this->MarginCorrection;
9015 $y = $this->tMargin; // mPDF 5.7.3
9016 $changedpage = true;
9017 }
9018 /* -- COLUMNS -- */
9019 // COLS
9020 // COLUMN CHANGE
9021 if ($this->CurrCol != $oldcolumn) {
9022 $y = $this->y0;
9023 $x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
9024 $this->x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
9025 }
9026 /* -- END COLUMNS -- */
9027 } // end of IF constrain
9028
9029 /* -- IMAGES-WMF -- */
9030 if ($info['type'] == 'wmf') {
9031 $sx = $w * Mpdf::SCALE / $info['w'];
9032 $sy = -$h * Mpdf::SCALE / $info['h'];
9033 $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * Mpdf::SCALE - $sx * $info['x'], (($this->h - $y) * Mpdf::SCALE) - $sy * $info['y'], $info['i']);
9034 } else { /* -- END IMAGES-WMF -- */
9035 if ($info['type'] == 'svg') {
9036 $sx = $w * Mpdf::SCALE / $info['w'];
9037 $sy = -$h * Mpdf::SCALE / $info['h'];
9038 $outstring = sprintf('q %.3F 0 0 %.3F %.3F %.3F cm /FO%d Do Q', $sx, $sy, $x * Mpdf::SCALE - $sx * $info['x'], (($this->h - $y) * Mpdf::SCALE) - $sy * $info['y'], $info['i']);
9039 } else {
9040 $outstring = sprintf("q %.3F 0 0 %.3F %.3F %.3F cm /I%d Do Q", $w * Mpdf::SCALE, $h * Mpdf::SCALE, $x * Mpdf::SCALE, ($this->h - ($y + $h)) * Mpdf::SCALE, $info['i']);
9041 }
9042 }
9043
9044 if ($paint) {
9045 $this->writer->write($outstring);
9046 if ($link) {
9047 $this->Link($x, $y, $w, $h, $link);
9048 }
9049
9050 // Avoid writing text on top of the image. // THIS WAS OUTSIDE THE if ($paint) bit!!!!!!!!!!!!!!!!
9051 $this->y = $y + $h;
9052 }
9053
9054 // Return width-height array
9055 $sizesarray['WIDTH'] = $w;
9056 $sizesarray['HEIGHT'] = $h;
9057 $sizesarray['X'] = $x; // Position before painting image
9058 $sizesarray['Y'] = $y; // Position before painting image
9059 $sizesarray['OUTPUT'] = $outstring;
9060
9061 $sizesarray['IMAGE_ID'] = $info['i'];
9062 $sizesarray['itype'] = $info['type'];
9063 $sizesarray['set-dpi'] = (isset($info['set-dpi']) ? $info['set-dpi'] : 0);
9064 return $sizesarray;
9065 }
9066
9067 // =============================================================
9068 // =============================================================
9069 // =============================================================
9070 // =============================================================
9071 // =============================================================
9072 /* -- HTML-CSS -- */
9073
9074 function _getObjAttr($t)
9075 {
9076 $c = explode("\xbb\xa4\xac", $t, 2);
9077 $c = explode(",", $c[1], 2);
9078 foreach ($c as $v) {
9079 $v = explode("=", $v, 2);
9080 $sp[$v[0]] = $v[1];
9081 }
9082 return (unserialize($sp['objattr']));
9083 }
9084
9085 function inlineObject($type, $x, $y, $objattr, $Lmargin, $widthUsed, $maxWidth, $lineHeight, $paint = false, $is_table = false)
9086 {
9087 if ($is_table) {
9088 $k = $this->shrin_k;
9089 } else {
9090 $k = 1;
9091 }
9092
9093 // NB $x is only used when paint=true
9094 // Lmargin not used
9095 $w = 0;
9096 if (isset($objattr['width'])) {
9097 $w = $objattr['width'] / $k;
9098 }
9099 $h = 0;
9100 if (isset($objattr['height'])) {
9101 $h = abs($objattr['height'] / $k);
9102 }
9103 $widthLeft = $maxWidth - $widthUsed;
9104 $maxHeight = $this->h - ($this->tMargin + $this->bMargin + 10);
9105 if ($this->fullImageHeight) {
9106 $maxHeight = $this->fullImageHeight;
9107 }
9108 // For Images
9109 if (isset($objattr['border_left'])) {
9110 $extraWidth = ($objattr['border_left']['w'] + $objattr['border_right']['w'] + $objattr['margin_left'] + $objattr['margin_right']) / $k;
9111 $extraHeight = ($objattr['border_top']['w'] + $objattr['border_bottom']['w'] + $objattr['margin_top'] + $objattr['margin_bottom']) / $k;
9112
9113 if ($type == 'image' || $type == 'barcode' || $type == 'textcircle') {
9114 $extraWidth += ($objattr['padding_left'] + $objattr['padding_right']) / $k;
9115 $extraHeight += ($objattr['padding_top'] + $objattr['padding_bottom']) / $k;
9116 }
9117 }
9118
9119 if (!isset($objattr['vertical-align'])) {
9120 if ($objattr['type'] == 'select') {
9121 $objattr['vertical-align'] = 'M';
9122 } else {
9123 $objattr['vertical-align'] = 'BS';
9124 }
9125 } // mPDF 6
9126
9127 if ($type == 'image' || (isset($objattr['subtype']) && $objattr['subtype'] == 'IMAGE')) {
9128 if (isset($objattr['itype']) && ($objattr['itype'] == 'wmf' || $objattr['itype'] == 'svg')) {
9129 $file = $objattr['file'];
9130 $info = $this->formobjects[$file];
9131 } elseif (isset($objattr['file'])) {
9132 $file = $objattr['file'];
9133 $info = $this->images[$file];
9134 }
9135 }
9136 if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') {
9137 $w = 0.00001;
9138 $h = 0.00001;
9139 }
9140
9141 // TEST whether need to skipline
9142 if (!$paint) {
9143 if ($type == 'hr') { // always force new line
9144 if (($y + $h + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) {
9145 return [-2, $w, $h];
9146 } // New page + new line
9147 else {
9148 return [1, $w, $h];
9149 } // new line
9150 } else {
9151 // LIST MARKERS // mPDF 6 Lists
9152 $displayheight = $h;
9153 $displaywidth = $w;
9154 if ($objattr['type'] == 'image' && isset($objattr['listmarker']) && $objattr['listmarker']) {
9155 $displayheight = 0;
9156 if ($objattr['listmarkerposition'] == 'outside') {
9157 $displaywidth = 0;
9158 }
9159 }
9160
9161 if ($widthUsed > 0 && $displaywidth > $widthLeft && (!$is_table || $type != 'image')) { // New line needed
9162 // mPDF 6 Lists
9163 if (($y + $displayheight + $lineHeight > $this->PageBreakTrigger) && !$this->InFooter) {
9164 return [-2, $w, $h];
9165 } // New page + new line
9166 return [1, $w, $h]; // new line
9167 } elseif ($widthUsed > 0 && $displaywidth > $widthLeft && $is_table) { // New line needed in TABLE
9168 return [1, $w, $h]; // new line
9169 } // Will fit on line but NEW PAGE REQUIRED
9170 elseif (($y + $displayheight > $this->PageBreakTrigger) && !$this->InFooter && !$is_table) {
9171 return [-1, $w, $h];
9172 } // mPDF 6 Lists
9173 else {
9174 return [0, $w, $h];
9175 }
9176 }
9177 }
9178
9179 if ($type == 'annot' || $type == 'bookmark' || $type == 'indexentry' || $type == 'toc') {
9180 $w = 0.00001;
9181 $h = 0.00001;
9182 $objattr['BORDER-WIDTH'] = 0;
9183 $objattr['BORDER-HEIGHT'] = 0;
9184 $objattr['BORDER-X'] = $x;
9185 $objattr['BORDER-Y'] = $y;
9186 $objattr['INNER-WIDTH'] = 0;
9187 $objattr['INNER-HEIGHT'] = 0;
9188 $objattr['INNER-X'] = $x;
9189 $objattr['INNER-Y'] = $y;
9190 }
9191
9192 if ($type == 'image') {
9193 // Automatically resize to width remaining
9194 if ($w > ($widthLeft + 0.0001) && !$is_table) { // mPDF 5.7.4 0.0001 to allow for rounding errors when w==maxWidth
9195 $w = $widthLeft;
9196 $h = abs($w * $info['h'] / $info['w']);
9197 }
9198 $img_w = $w - $extraWidth;
9199 $img_h = $h - $extraHeight;
9200
9201 $objattr['BORDER-WIDTH'] = $img_w + $objattr['padding_left'] / $k + $objattr['padding_right'] / $k + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
9202 $objattr['BORDER-HEIGHT'] = $img_h + $objattr['padding_top'] / $k + $objattr['padding_bottom'] / $k + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
9203 $objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
9204 $objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
9205 $objattr['INNER-WIDTH'] = $img_w;
9206 $objattr['INNER-HEIGHT'] = $img_h;
9207 $objattr['INNER-X'] = $x + $objattr['padding_left'] / $k + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
9208 $objattr['INNER-Y'] = $y + $objattr['padding_top'] / $k + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
9209 $objattr['ID'] = $info['i'];
9210 }
9211
9212 if ($type == 'input' && $objattr['subtype'] == 'IMAGE') {
9213 $img_w = $w - $extraWidth;
9214 $img_h = $h - $extraHeight;
9215 $objattr['BORDER-WIDTH'] = $img_w + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
9216 $objattr['BORDER-HEIGHT'] = $img_h + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
9217 $objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
9218 $objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
9219 $objattr['INNER-WIDTH'] = $img_w;
9220 $objattr['INNER-HEIGHT'] = $img_h;
9221 $objattr['INNER-X'] = $x + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
9222 $objattr['INNER-Y'] = $y + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
9223 $objattr['ID'] = $info['i'];
9224 }
9225
9226 if ($type == 'barcode' || $type == 'textcircle') {
9227 $b_w = $w - $extraWidth;
9228 $b_h = $h - $extraHeight;
9229 $objattr['BORDER-WIDTH'] = $b_w + $objattr['padding_left'] / $k + $objattr['padding_right'] / $k + (($objattr['border_left']['w'] / $k + $objattr['border_right']['w'] / $k) / 2);
9230 $objattr['BORDER-HEIGHT'] = $b_h + $objattr['padding_top'] / $k + $objattr['padding_bottom'] / $k + (($objattr['border_top']['w'] / $k + $objattr['border_bottom']['w'] / $k) / 2);
9231 $objattr['BORDER-X'] = $x + $objattr['margin_left'] / $k + (($objattr['border_left']['w'] / $k) / 2);
9232 $objattr['BORDER-Y'] = $y + $objattr['margin_top'] / $k + (($objattr['border_top']['w'] / $k) / 2);
9233 $objattr['INNER-X'] = $x + $objattr['padding_left'] / $k + $objattr['margin_left'] / $k + ($objattr['border_left']['w'] / $k);
9234 $objattr['INNER-Y'] = $y + $objattr['padding_top'] / $k + $objattr['margin_top'] / $k + ($objattr['border_top']['w'] / $k);
9235 $objattr['INNER-WIDTH'] = $b_w;
9236 $objattr['INNER-HEIGHT'] = $b_h;
9237 }
9238
9239
9240 if ($type == 'textarea') {
9241 // Automatically resize to width remaining
9242 if ($w > $widthLeft && !$is_table) {
9243 $w = $widthLeft;
9244 }
9245 // This used to resize height to maximum remaining on page ? why. Causes problems when in table and causing a new column
9246 // if (($y + $h > $this->PageBreakTrigger) && !$this->InFooter) {
9247 // $h=$this->h - $y - $this->bMargin;
9248 // }
9249 }
9250
9251 if ($type == 'hr') {
9252 if ($is_table) {
9253 $objattr['INNER-WIDTH'] = $maxWidth * $objattr['W-PERCENT'] / 100;
9254 $objattr['width'] = $objattr['INNER-WIDTH'];
9255 $w = $maxWidth;
9256 } else {
9257 if ($w > $maxWidth) {
9258 $w = $maxWidth;
9259 }
9260 $objattr['INNER-WIDTH'] = $w;
9261 $w = $maxWidth;
9262 }
9263 }
9264
9265
9266
9267 if (($type == 'select') || ($type == 'input' && ($objattr['subtype'] == 'TEXT' || $objattr['subtype'] == 'PASSWORD'))) {
9268 // Automatically resize to width remaining
9269 if ($w > $widthLeft && !$is_table) {
9270 $w = $widthLeft;
9271 }
9272 }
9273
9274 if ($type == 'textarea' || $type == 'select' || $type == 'input') {
9275 if (isset($objattr['fontsize'])) {
9276 $objattr['fontsize'] /= $k;
9277 }
9278 if (isset($objattr['linewidth'])) {
9279 $objattr['linewidth'] /= $k;
9280 }
9281 }
9282
9283 if (!isset($objattr['BORDER-Y'])) {
9284 $objattr['BORDER-Y'] = 0;
9285 }
9286 if (!isset($objattr['BORDER-X'])) {
9287 $objattr['BORDER-X'] = 0;
9288 }
9289 if (!isset($objattr['INNER-Y'])) {
9290 $objattr['INNER-Y'] = 0;
9291 }
9292 if (!isset($objattr['INNER-X'])) {
9293 $objattr['INNER-X'] = 0;
9294 }
9295
9296 // Return width-height array
9297 $objattr['OUTER-WIDTH'] = $w;
9298 $objattr['OUTER-HEIGHT'] = $h;
9299 $objattr['OUTER-X'] = $x;
9300 $objattr['OUTER-Y'] = $y;
9301 return $objattr;
9302 }
9303
9304 /* -- END HTML-CSS -- */
9305
9306 // =============================================================
9307 // =============================================================
9308 // =============================================================
9309 // =============================================================
9310 // =============================================================
9311
9312 function SetLineJoin($mode = 0)
9313 {
9314 $s = sprintf('%d j', $mode);
9315 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineJoin']) && $this->pageoutput[$this->page]['LineJoin'] != $s) || !isset($this->pageoutput[$this->page]['LineJoin']))) {
9316 $this->writer->write($s);
9317 }
9318 $this->pageoutput[$this->page]['LineJoin'] = $s;
9319 }
9320
9321 function SetLineCap($mode = 2)
9322 {
9323 $s = sprintf('%d J', $mode);
9324 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['LineCap']) && $this->pageoutput[$this->page]['LineCap'] != $s) || !isset($this->pageoutput[$this->page]['LineCap']))) {
9325 $this->writer->write($s);
9326 }
9327 $this->pageoutput[$this->page]['LineCap'] = $s;
9328 }
9329
9330 function SetDash($black = false, $white = false)
9331 {
9332 if ($black and $white) {
9333 $s = sprintf('[%.3F %.3F] 0 d', $black * Mpdf::SCALE, $white * Mpdf::SCALE);
9334 } else {
9335 $s = '[] 0 d';
9336 }
9337
9338 if ($this->page > 0 && ((isset($this->pageoutput[$this->page]['Dash']) && $this->pageoutput[$this->page]['Dash'] != $s) || !isset($this->pageoutput[$this->page]['Dash']))) {
9339 $this->writer->write($s);
9340 }
9341
9342 $this->pageoutput[$this->page]['Dash'] = $s;
9343 }
9344
9345 function SetDisplayPreferences($preferences)
9346 {
9347 // String containing any or none of /HideMenubar/HideToolbar/HideWindowUI/DisplayDocTitle/CenterWindow/FitWindow
9348
9349 $this->DisplayPreferences .= $preferences;
9350 }
9351
9352 function Ln($h = '', $collapsible = 0)
9353 {
9354 // Added collapsible to allow collapsible top-margin on new page
9355 // Line feed; default value is last cell height
9356
9357 $margin = isset($this->blk[$this->blklvl]['outer_left_margin']) ? $this->blk[$this->blklvl]['outer_left_margin'] : 0;
9358
9359 $this->x = $this->lMargin + $margin;
9360
9361 if ($collapsible && ($this->y == $this->tMargin) && (!$this->ColActive)) {
9362 $h = 0;
9363 }
9364
9365 if (is_string($h)) {
9366 $this->y += $this->lasth;
9367 } else {
9368 $this->y += $h;
9369 }
9370 }
9371
9372 /* -- HTML-CSS -- */
9373
9374 function DivLn($h, $level = -3, $move_y = true, $collapsible = false, $state = 0)
9375 {
9376 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
9377 // Used in Columns and keep-with-table i.e. "kwt"
9378 // writes background block by block so it can be repositioned
9379 // and also used in writingFlowingBlock at top and bottom of blocks to move y (not to draw/paint anything)
9380 // adds lines (y) where DIV bgcolors are filled in
9381 // this->x is returned as it was
9382 // allows .00001 as nominal height used for bookmarks/annotations etc.
9383 if ($collapsible && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->tMargin)) && (!$this->ColActive)) {
9384 return;
9385 }
9386
9387 // mPDF 6 Columns
9388 // if ($collapsible && (sprintf("%0.4f", $this->y)==sprintf("%0.4f", $this->y0)) && ($this->ColActive) && $this->CurrCol == 0) { return; } // *COLUMNS*
9389 if ($collapsible && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->y0)) && ($this->ColActive)) {
9390 return;
9391 } // *COLUMNS*
9392 // Still use this method if columns or keep-with-table, as it allows repositioning later
9393 // otherwise, now uses PaintDivBB()
9394 if (!$this->ColActive && !$this->kwt) {
9395 if ($move_y && !$this->ColActive) {
9396 $this->y += $h;
9397 }
9398 return;
9399 }
9400
9401 if ($level == -3) {
9402 $level = $this->blklvl;
9403 }
9404 $firstblockfill = $this->GetFirstBlockFill();
9405 if ($firstblockfill && $this->blklvl > 0 && $this->blklvl >= $firstblockfill) {
9406 $last_x = 0;
9407 $last_w = 0;
9408 $last_fc = $this->FillColor;
9409 $bak_x = $this->x;
9410 $bak_h = $this->divheight;
9411 $this->divheight = 0; // Temporarily turn off divheight - as Cell() uses it to check for PageBreak
9412 for ($blvl = $firstblockfill; $blvl <= $level; $blvl++) {
9413 $this->x = $this->lMargin + $this->blk[$blvl]['outer_left_margin'];
9414 // mPDF 6
9415 if ($this->blk[$blvl]['bgcolor']) {
9416 $this->SetFColor($this->blk[$blvl]['bgcolorarray']);
9417 }
9418 if ($last_x != ($this->lMargin + $this->blk[$blvl]['outer_left_margin']) || ($last_w != $this->blk[$blvl]['width']) || $last_fc != $this->FillColor || (isset($this->blk[$blvl]['border_top']['s']) && $this->blk[$blvl]['border_top']['s']) || (isset($this->blk[$blvl]['border_bottom']['s']) && $this->blk[$blvl]['border_bottom']['s']) || (isset($this->blk[$blvl]['border_left']['s']) && $this->blk[$blvl]['border_left']['s']) || (isset($this->blk[$blvl]['border_right']['s']) && $this->blk[$blvl]['border_right']['s'])) {
9419 $x = $this->x;
9420 $this->Cell(($this->blk[$blvl]['width']), $h, '', '', 0, '', 1);
9421 $this->x = $x;
9422 if (!$this->keep_block_together && !$this->writingHTMLheader && !$this->writingHTMLfooter) {
9423 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
9424 if ($blvl == $this->blklvl) {
9425 $this->PaintDivLnBorder($state, $blvl, $h);
9426 } else {
9427 $this->PaintDivLnBorder(0, $blvl, $h);
9428 }
9429 }
9430 }
9431 $last_x = $this->lMargin + $this->blk[$blvl]['outer_left_margin'];
9432 $last_w = $this->blk[$blvl]['width'];
9433 $last_fc = $this->FillColor;
9434 }
9435 // Reset current block fill
9436 if (isset($this->blk[$this->blklvl]['bgcolorarray'])) {
9437 $bcor = $this->blk[$this->blklvl]['bgcolorarray'];
9438 $this->SetFColor($bcor);
9439 }
9440 $this->x = $bak_x;
9441 $this->divheight = $bak_h;
9442 }
9443 if ($move_y) {
9444 $this->y += $h;
9445 }
9446 }
9447
9448 /* -- END HTML-CSS -- */
9449
9450 function SetX($x)
9451 {
9452 // Set x position
9453 if ($x >= 0) {
9454 $this->x = $x;
9455 } else {
9456 $this->x = $this->w + $x;
9457 }
9458 }
9459
9460 function SetY($y)
9461 {
9462 // Set y position and reset x
9463 $this->x = $this->lMargin;
9464 if ($y >= 0) {
9465 $this->y = $y;
9466 } else {
9467 $this->y = $this->h + $y;
9468 }
9469 }
9470
9471 function SetXY($x, $y)
9472 {
9473 // Set x and y positions
9474 $this->SetY($y);
9475 $this->SetX($x);
9476 }
9477
9478 function Output($name = '', $dest = '')
9479 {
9480 $this->logger->debug(sprintf('PDF generated in %.6F seconds', microtime(true) - $this->time0), ['context' => LogContext::STATISTICS]);
9481
9482 // Finish document if necessary
9483 if ($this->state < 3) {
9484 $this->Close();
9485 }
9486
9487 if ($this->debug && error_get_last()) {
9488 $e = error_get_last();
9489 if (($e['type'] < 2048 && $e['type'] != 8) || (intval($e['type']) & intval(ini_get("error_reporting")))) {
9490 throw new \Mpdf\MpdfException(
9491 sprintf('Error detected. PDF file generation aborted: %s', $e['message']),
9492 $e['type'],
9493 1,
9494 $e['file'],
9495 $e['line']
9496 );
9497 }
9498 }
9499
9500 if (($this->PDFA || $this->PDFX) && $this->encrypted) {
9501 throw new \Mpdf\MpdfException('PDF/A1-b or PDF/X1-a does not permit encryption of documents.');
9502 }
9503
9504 if (count($this->PDFAXwarnings) && (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto))) {
9505 if ($this->PDFA) {
9506 $standard = 'PDFA/1-b';
9507 $option = '$mpdf->PDFAauto';
9508 } else {
9509 $standard = 'PDFX/1-a ';
9510 $option = '$mpdf->PDFXauto';
9511 }
9512
9513 $this->logger->warning(sprintf('PDF could not be generated as it stands as a %s compliant file.', $standard), ['context' => LogContext::PDFA_PDFX]);
9514 $this->logger->warning(sprintf('These issues can be automatically fixed by mPDF using %s = true;', $option), ['context' => LogContext::PDFA_PDFX]);
9515 $this->logger->warning(sprintf('Action that mPDF will take to automatically force %s compliance are shown further in the log.', $standard), ['context' => LogContext::PDFA_PDFX]);
9516
9517 $this->PDFAXwarnings = array_unique($this->PDFAXwarnings);
9518 foreach ($this->PDFAXwarnings as $w) {
9519 $this->logger->warning($w, ['context' => LogContext::PDFA_PDFX]);
9520 }
9521
9522 throw new \Mpdf\MpdfException('PDFA/PDFX warnings generated. See log for further details');
9523 }
9524
9525 $this->logger->debug(sprintf('Compiled in %.6F seconds', microtime(true) - $this->time0), ['context' => LogContext::STATISTICS]);
9526 $this->logger->debug(sprintf('Peak Memory usage %s MB', number_format(memory_get_peak_usage(true) / (1024 * 1024), 2)), ['context' => LogContext::STATISTICS]);
9527 $this->logger->debug(sprintf('PDF file size %s kB', number_format(strlen($this->buffer) / 1024)), ['context' => LogContext::STATISTICS]);
9528 $this->logger->debug(sprintf('%d fonts used', count($this->fonts)), ['context' => LogContext::STATISTICS]);
9529
9530 if (is_bool($dest)) {
9532 }
9533
9534 $dest = strtoupper($dest);
9535 if (empty($dest)) {
9536 if (empty($name)) {
9537 $name = 'mpdf.pdf';
9539 } else {
9541 }
9542 }
9543
9544 switch ($dest) {
9545
9547
9548 if (headers_sent($filename, $line)) {
9549 throw new \Mpdf\MpdfException(
9550 sprintf('Data has already been sent to output (%s at line %s), unable to output PDF file', $filename, $line)
9551 );
9552 }
9553
9554 if ($this->debug && !$this->allow_output_buffering && ob_get_contents()) {
9555 throw new \Mpdf\MpdfException('Output has already been sent from the script - PDF file generation aborted.');
9556 }
9557
9558 // We send to a browser
9559 if (PHP_SAPI !== 'cli') {
9560 header('Content-Type: application/pdf');
9561
9562 if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) || empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
9563 // don't use length if server using compression
9564 header('Content-Length: ' . strlen($this->buffer));
9565 }
9566
9567 header('Content-disposition: inline; filename="' . $name . '"');
9568 header('Cache-Control: public, must-revalidate, max-age=0');
9569 header('Pragma: public');
9570 header('X-Generator: mPDF' . ($this->exposeVersion ? (' ' . static::VERSION) : ''));
9571 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
9572 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
9573 }
9574
9575 echo $this->buffer;
9576
9577 break;
9578
9580
9581 if (headers_sent()) {
9582 throw new \Mpdf\MpdfException('Data has already been sent to output, unable to output PDF file');
9583 }
9584
9585 header('Content-Description: File Transfer');
9586 header('Content-Transfer-Encoding: binary');
9587 header('Cache-Control: public, must-revalidate, max-age=0');
9588 header('Pragma: public');
9589 header('X-Generator: mPDF' . ($this->exposeVersion ? (' ' . static::VERSION) : ''));
9590 header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
9591 header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
9592 header('Content-Type: application/pdf');
9593
9594 if (!isset($_SERVER['HTTP_ACCEPT_ENCODING']) || empty($_SERVER['HTTP_ACCEPT_ENCODING'])) {
9595 // don't use length if server using compression
9596 header('Content-Length: ' . strlen($this->buffer));
9597 }
9598
9599 header('Content-Disposition: attachment; filename="' . $name . '"');
9600
9601 echo $this->buffer;
9602
9603 break;
9604
9605 case Destination::FILE:
9606 $f = fopen($name, 'wb');
9607
9608 if (!$f) {
9609 throw new \Mpdf\MpdfException(sprintf('Unable to create output file %s', $name));
9610 }
9611
9612 fwrite($f, $this->buffer, strlen($this->buffer));
9613 fclose($f);
9614
9615 break;
9616
9618 $this->cache->clearOld();
9619 return $this->buffer;
9620
9621 default:
9622 throw new \Mpdf\MpdfException(sprintf('Incorrect output destination %s', $dest));
9623 }
9624
9625 $this->cache->clearOld();
9626 }
9627
9628 // *****************************************************************************
9629 // *
9630 // Protected methods *
9631 // *
9632 // *****************************************************************************
9633 function _dochecks()
9634 {
9635 // Check for locale-related bug
9636 if (1.1 == 1) {
9637 throw new \Mpdf\MpdfException('Do not alter the locale before including mPDF');
9638 }
9639
9640 // Check for decimal separator
9641 if (sprintf('%.1f', 1.0) != '1.0') {
9642 setlocale(LC_NUMERIC, 'C');
9643 }
9644
9645 if (ini_get('mbstring.func_overload')) {
9646 throw new \Mpdf\MpdfException('Mpdf cannot function properly with mbstring.func_overload enabled');
9647 }
9648
9649 if (!function_exists('mb_substr')) {
9650 throw new \Mpdf\MpdfException('mbstring extension must be loaded in order to run mPDF');
9651 }
9652
9653 if (!function_exists('mb_regex_encoding')) {
9654 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
9655 $mamp = ' If using MAMP, there is a bug in its PHP build causing this.';
9656 }
9657
9658 throw new \Mpdf\MpdfException('mbstring extension with mbregex support must be loaded in order to run mPDF.' . $mamp);
9659 }
9660 }
9661
9663 {
9664 $this->state = 2;
9665 $nb = $this->page;
9666 for ($n = 1; $n <= $nb; $n++) {
9667 if ($this->mirrorMargins && $n % 2 == 0) {
9668 $OE = 'E';
9669 } // EVEN
9670 else {
9671 $OE = 'O';
9672 }
9673 $this->page = $n;
9674 $pn = $this->docPageNum($n);
9675 if ($pn) {
9676 $pnstr = $this->pagenumPrefix . $pn . $this->pagenumSuffix;
9677 } else {
9678 $pnstr = '';
9679 }
9680
9681 $pnt = $this->docPageNumTotal($n);
9682
9683 if ($pnt) {
9684 $pntstr = $this->nbpgPrefix . $pnt . $this->nbpgSuffix;
9685 } else {
9686 $pntstr = '';
9687 }
9688
9689 if (isset($this->saveHTMLHeader[$n][$OE])) {
9690 $html = isset($this->saveHTMLHeader[$n][$OE]['html']) ? $this->saveHTMLHeader[$n][$OE]['html'] : '';
9691 $this->lMargin = $this->saveHTMLHeader[$n][$OE]['ml'];
9692 $this->rMargin = $this->saveHTMLHeader[$n][$OE]['mr'];
9693 $this->tMargin = $this->saveHTMLHeader[$n][$OE]['mh'];
9694 $this->bMargin = $this->saveHTMLHeader[$n][$OE]['mf'];
9695 $this->margin_header = $this->saveHTMLHeader[$n][$OE]['mh'];
9696 $this->margin_footer = $this->saveHTMLHeader[$n][$OE]['mf'];
9697 $this->w = $this->saveHTMLHeader[$n][$OE]['pw'];
9698 $this->h = $this->saveHTMLHeader[$n][$OE]['ph'];
9699 $rotate = (isset($this->saveHTMLHeader[$n][$OE]['rotate']) ? $this->saveHTMLHeader[$n][$OE]['rotate'] : null);
9700 $this->Reset();
9701 $this->pageoutput[$n] = [];
9702 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
9703 $this->x = $this->lMargin;
9704 $this->y = $this->margin_header;
9705
9706 // Replace of page number aliases and date format
9707 $html = $this->aliasReplace($html, $pnstr, $pntstr, $nb);
9708
9709 $this->HTMLheaderPageLinks = [];
9710 $this->HTMLheaderPageAnnots = [];
9711 $this->HTMLheaderPageForms = [];
9712 $this->pageBackgrounds = [];
9713
9714 $this->writingHTMLheader = true;
9715 $this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
9716 $this->writingHTMLheader = false;
9717 $this->Reset();
9718 $this->pageoutput[$n] = [];
9719
9720 $s = $this->PrintPageBackgrounds();
9721 $this->headerbuffer = $s . $this->headerbuffer;
9722 $os = '';
9723 if ($rotate) {
9724 $os .= sprintf('q 0 -1 1 0 0 %.3F cm ', ($this->w * Mpdf::SCALE));
9725 // To rotate the other way i.e. Header to left of page:
9726 // $os .= sprintf('q 0 1 -1 0 %.3F %.3F cm ',($this->h*Mpdf::SCALE), (($this->rMargin - $this->lMargin )*Mpdf::SCALE));
9727 }
9728 $os .= $this->headerbuffer;
9729 if ($rotate) {
9730 $os .= ' Q' . "\n";
9731 }
9732
9733 // Writes over the page background but behind any other output on page
9734 $os = preg_replace(['/\\\\/', '/\$/'], ['\\\\\\\\', '\\\\$'], $os);
9735
9736 $this->pages[$n] = preg_replace('/(___HEADER___MARKER' . $this->uniqstr . ')/', "\n" . $os . "\n" . '\\1', $this->pages[$n]);
9737
9738 $lks = $this->HTMLheaderPageLinks;
9739 foreach ($lks as $lk) {
9740 if ($rotate) {
9741 $lw = $lk[2];
9742 $lh = $lk[3];
9743 $lk[2] = $lh;
9744 $lk[3] = $lw; // swap width and height
9745 $ax = $lk[0] / Mpdf::SCALE;
9746 $ay = $lk[1] / Mpdf::SCALE;
9747 $bx = $ay - ($lh / Mpdf::SCALE);
9748 $by = $this->w - $ax;
9749 $lk[0] = $bx * Mpdf::SCALE;
9750 $lk[1] = ($this->h - $by) * Mpdf::SCALE - $lw;
9751 }
9752 $this->PageLinks[$n][] = $lk;
9753 }
9754 /* -- FORMS -- */
9755 foreach ($this->HTMLheaderPageForms as $f) {
9756 $this->form->forms[$f['n']] = $f;
9757 }
9758 /* -- END FORMS -- */
9759 }
9760
9761 if (isset($this->saveHTMLFooter[$n][$OE])) {
9762
9763 $html = $this->saveHTMLFooter[$this->page][$OE]['html'];
9764
9765 $this->lMargin = $this->saveHTMLFooter[$n][$OE]['ml'];
9766 $this->rMargin = $this->saveHTMLFooter[$n][$OE]['mr'];
9767 $this->tMargin = $this->saveHTMLFooter[$n][$OE]['mh'];
9768 $this->bMargin = $this->saveHTMLFooter[$n][$OE]['mf'];
9769 $this->margin_header = $this->saveHTMLFooter[$n][$OE]['mh'];
9770 $this->margin_footer = $this->saveHTMLFooter[$n][$OE]['mf'];
9771 $this->w = $this->saveHTMLFooter[$n][$OE]['pw'];
9772 $this->h = $this->saveHTMLFooter[$n][$OE]['ph'];
9773 $rotate = (isset($this->saveHTMLFooter[$n][$OE]['rotate']) ? $this->saveHTMLFooter[$n][$OE]['rotate'] : null);
9774 $this->Reset();
9775 $this->pageoutput[$n] = [];
9776 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
9777 $this->x = $this->lMargin;
9778 $top_y = $this->y = $this->h - $this->margin_footer;
9779
9780 // if bottom-margin==0, corrects to avoid division by zero
9781 if ($this->y == $this->h) {
9782 $top_y = $this->y = ($this->h + 0.01);
9783 }
9784
9785 // Replace of page number aliases and date format
9786 $html = $this->aliasReplace($html, $pnstr, $pntstr, $nb);
9787
9788 $this->HTMLheaderPageLinks = [];
9789 $this->HTMLheaderPageAnnots = [];
9790 $this->HTMLheaderPageForms = [];
9791 $this->pageBackgrounds = [];
9792
9793 $this->writingHTMLfooter = true;
9794 $this->InFooter = true;
9795 $this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
9796 $this->InFooter = false;
9797 $this->Reset();
9798 $this->pageoutput[$n] = [];
9799
9800 $fheight = $this->y - $top_y;
9801 $adj = -$fheight;
9802
9803 $s = $this->PrintPageBackgrounds(-$adj);
9804 $this->headerbuffer = $s . $this->headerbuffer;
9805 $this->writingHTMLfooter = false; // mPDF 5.7.3 (moved after PrintPageBackgrounds so can adjust position of images in footer)
9806
9807 $os = '';
9808 $os .= $this->StartTransform(true) . "\n";
9809
9810 if ($rotate) {
9811 $os .= sprintf('q 0 -1 1 0 0 %.3F cm ', ($this->w * Mpdf::SCALE));
9812 // To rotate the other way i.e. Header to left of page:
9813 // $os .= sprintf('q 0 1 -1 0 %.3F %.3F cm ',($this->h*Mpdf::SCALE), (($this->rMargin - $this->lMargin )*Mpdf::SCALE));
9814 }
9815
9816 $os .= $this->transformTranslate(0, $adj, true) . "\n";
9817 $os .= $this->headerbuffer;
9818
9819 if ($rotate) {
9820 $os .= ' Q' . "\n";
9821 }
9822
9823 $os .= $this->StopTransform(true) . "\n";
9824
9825 // Writes over the page background but behind any other output on page
9826 $os = preg_replace(['/\\\\/', '/\$/'], ['\\\\\\\\', '\\\\$'], $os);
9827
9828 $this->pages[$n] = preg_replace('/(___HEADER___MARKER' . $this->uniqstr . ')/', "\n" . $os . "\n" . '\\1', $this->pages[$n]);
9829
9830 $lks = $this->HTMLheaderPageLinks;
9831
9832 foreach ($lks as $lk) {
9833
9834 $lk[1] -= $adj * Mpdf::SCALE;
9835
9836 if ($rotate) {
9837 $lw = $lk[2];
9838 $lh = $lk[3];
9839 $lk[2] = $lh;
9840 $lk[3] = $lw; // swap width and height
9841
9842 $ax = $lk[0] / Mpdf::SCALE;
9843 $ay = $lk[1] / Mpdf::SCALE;
9844 $bx = $ay - ($lh / Mpdf::SCALE);
9845 $by = $this->w - $ax;
9846 $lk[0] = $bx * Mpdf::SCALE;
9847 $lk[1] = ($this->h - $by) * Mpdf::SCALE - $lw;
9848 }
9849
9850 $this->PageLinks[$n][] = $lk;
9851 }
9852
9853 /* -- FORMS -- */
9854 foreach ($this->HTMLheaderPageForms as $f) {
9855 $f['y'] += $adj;
9856 $this->form->forms[$f['n']] = $f;
9857 }
9858 /* -- END FORMS -- */
9859 }
9860
9861 // Customization for https://github.com/mpdf/mpdf/issues/172
9862 // Replace of page number aliases and date format
9863 $this->pages[$n] = $this->aliasReplace($this->pages[$n], $pnstr, $pntstr, $nb);
9864 }
9865
9866 $this->page = $nb;
9867 $this->state = 1;
9868 }
9869
9870 /* -- ANNOTATIONS -- */
9871 function Annotation($text, $x = 0, $y = 0, $icon = 'Note', $author = '', $subject = '', $opacity = 0, $colarray = false, $popup = '', $file = '')
9872 {
9873 if (is_array($colarray) && count($colarray) == 3) {
9874 $colarray = $this->colorConverter->convert('rgb(' . $colarray[0] . ',' . $colarray[1] . ',' . $colarray[2] . ')', $this->PDFAXwarnings);
9875 }
9876 if ($colarray === false) {
9877 $colarray = $this->colorConverter->convert('yellow', $this->PDFAXwarnings);
9878 }
9879 if ($x == 0) {
9880 $x = $this->x;
9881 }
9882 if ($y == 0) {
9883 $y = $this->y;
9884 }
9885 $page = $this->page;
9886 if ($page < 1) { // Document has not been started - assume it's for first page
9887 $page = 1;
9888 if ($x == 0) {
9889 $x = $this->lMargin;
9890 }
9891 if ($y == 0) {
9892 $y = $this->tMargin;
9893 }
9894 }
9895
9896 if ($this->PDFA || $this->PDFX) {
9897 if (($this->PDFA && !$this->PDFAauto) || ($this->PDFX && !$this->PDFXauto)) {
9898 $this->PDFAXwarnings[] = "Annotation markers cannot be semi-transparent in PDFA1-b or PDFX/1-a, so they may make underlying text unreadable. (Annotation markers moved to right margin)";
9899 }
9900 $x = ($this->w) - $this->rMargin * 0.66;
9901 }
9902 if (!$this->annotMargin) {
9903 $y -= $this->FontSize / 2;
9904 }
9905
9906 if (!$opacity && $this->annotMargin) {
9907 $opacity = 1;
9908 } elseif (!$opacity) {
9909 $opacity = $this->annotOpacity;
9910 }
9911
9912 $an = ['txt' => $text, 'x' => $x, 'y' => $y, 'opt' => ['Icon' => $icon, 'T' => $author, 'Subj' => $subject, 'C' => $colarray, 'CA' => $opacity, 'popup' => $popup, 'file' => $file]];
9913
9914 if ($this->keep_block_together) { // don't write yet
9915 return;
9916 } elseif ($this->table_rotate) {
9917 $this->tbrot_Annots[$this->page][] = $an;
9918 return;
9919 } elseif ($this->kwt) {
9920 $this->kwt_Annots[$this->page][] = $an;
9921 return;
9922 }
9923
9924 if ($this->writingHTMLheader || $this->writingHTMLfooter) {
9925 $this->HTMLheaderPageAnnots[] = $an;
9926 return;
9927 }
9928
9929 // Put an Annotation on the page
9930 $this->PageAnnots[$page][] = $an;
9931
9932 /* -- COLUMNS -- */
9933 // Save cross-reference to Column buffer
9934 $ref = isset($this->PageAnnots[$this->page]) ? (count($this->PageAnnots[$this->page]) - 1) : -1;
9935 $this->columnAnnots[$this->CurrCol][intval($this->x)][intval($this->y)] = $ref;
9936 /* -- END COLUMNS -- */
9937 }
9938
9939 /* -- END ANNOTATIONS -- */
9940
9941 function _enddoc()
9942 {
9943 // @log Writing Headers & Footers
9944
9945 $this->_puthtmlheaders();
9946
9947 // @log Writing Pages
9948
9949 // Remove references to unused fonts (usually default font)
9950 foreach ($this->fonts as $fk => $font) {
9951 if (isset($font['type']) && $font['type'] == 'TTF' && !$font['used']) {
9952 if ($font['sip'] || $font['smp']) {
9953 foreach ($font['subsetfontids'] as $k => $fid) {
9954 foreach ($this->pages as $pn => $page) {
9955 $this->pages[$pn] = preg_replace('/\s\/F' . $fid . ' \d[\d.]* Tf\s/is', ' ', $this->pages[$pn]);
9956 }
9957 }
9958 } else {
9959 foreach ($this->pages as $pn => $page) {
9960 $this->pages[$pn] = preg_replace('/\s\/F' . $font['i'] . ' \d[\d.]* Tf\s/is', ' ', $this->pages[$pn]);
9961 }
9962 }
9963 }
9964 }
9965
9966 if (count($this->layers)) {
9967 foreach ($this->pages as $pn => $page) {
9968 preg_match_all('/\/OCZ-index \/ZI(\d+) BDC(.*?)(EMCZ)-index/is', $this->pages[$pn], $m1);
9969 preg_match_all('/\/OCBZ-index \/ZI(\d+) BDC(.*?)(EMCBZ)-index/is', $this->pages[$pn], $m2);
9970 preg_match_all('/\/OCGZ-index \/ZI(\d+) BDC(.*?)(EMCGZ)-index/is', $this->pages[$pn], $m3);
9971 $m = [];
9972 for ($i = 0; $i < 4; $i++) {
9973 $m[$i] = array_merge($m1[$i], $m2[$i], $m3[$i]);
9974 }
9975 if (count($m[0])) {
9976 $sortarr = [];
9977 for ($i = 0; $i < count($m[0]); $i++) {
9978 $key = $m[1][$i] * 2;
9979 if ($m[3][$i] == 'EMCZ') {
9980 $key +=2; // background first then gradient then normal
9981 } elseif ($m[3][$i] == 'EMCGZ') {
9982 $key +=1;
9983 }
9984 $sortarr[$i] = $key;
9985 }
9986 asort($sortarr);
9987 foreach ($sortarr as $i => $k) {
9988 $this->pages[$pn] = str_replace($m[0][$i], '', $this->pages[$pn]);
9989 $this->pages[$pn] .= "\n" . $m[0][$i] . "\n";
9990 }
9991 $this->pages[$pn] = preg_replace('/\/OC[BG]{0,1}Z-index \/ZI(\d+) BDC/is', '/OC /ZI\\1 BDC ', $this->pages[$pn]);
9992 $this->pages[$pn] = preg_replace('/EMC[BG]{0,1}Z-index/is', 'EMC', $this->pages[$pn]);
9993 }
9994 }
9995 }
9996
9997 $this->pageWriter->writePages();
9998
9999 // @log Writing document resources
10000
10001 $this->resourceWriter->writeResources();
10002
10003 // Info
10004 $this->writer->object();
10005 $this->InfoRoot = $this->n;
10006 $this->writer->write('<<');
10007
10008 // @log Writing document info
10009 $this->metadataWriter->writeInfo();
10010
10011 $this->writer->write('>>');
10012 $this->writer->write('endobj');
10013
10014 // METADATA
10015 if ($this->PDFA || $this->PDFX) {
10016 $this->metadataWriter->writeMetadata();
10017 }
10018
10019 // OUTPUTINTENT
10020 if ($this->PDFA || $this->PDFX || $this->ICCProfile) {
10021 $this->metadataWriter->writeOutputIntent();
10022 }
10023
10024 // Associated files
10025 if ($this->associatedFiles) {
10026 $this->metadataWriter->writeAssociatedFiles();
10027 }
10028
10029 // Catalog
10030 $this->writer->object();
10031 $this->writer->write('<<');
10032
10033 // @log Writing document catalog
10034
10035 $this->metadataWriter->writeCatalog();
10036
10037 $this->writer->write('>>');
10038 $this->writer->write('endobj');
10039
10040 // Cross-ref
10041 $o = strlen($this->buffer);
10042 $this->writer->write('xref');
10043 $this->writer->write('0 ' . ($this->n + 1));
10044 $this->writer->write('0000000000 65535 f ');
10045
10046 for ($i = 1; $i <= $this->n; $i++) {
10047 $this->writer->write(sprintf('%010d 00000 n ', $this->offsets[$i]));
10048 }
10049
10050 // Trailer
10051 $this->writer->write('trailer');
10052 $this->writer->write('<<');
10053
10054 $this->metadataWriter->writeTrailer();
10055
10056 $this->writer->write('>>');
10057 $this->writer->write('startxref');
10058 $this->writer->write($o);
10059
10060 $this->buffer .= '%%EOF';
10061 $this->state = 3;
10062 }
10063
10064 function _beginpage(
10065 $orientation,
10066 $mgl = '',
10067 $mgr = '',
10068 $mgt = '',
10069 $mgb = '',
10070 $mgh = '',
10071 $mgf = '',
10072 $ohname = '',
10073 $ehname = '',
10074 $ofname = '',
10075 $efname = '',
10076 $ohvalue = 0,
10077 $ehvalue = 0,
10078 $ofvalue = 0,
10079 $efvalue = 0,
10080 $pagesel = '',
10081 $newformat = ''
10082 ) {
10083 if (!($pagesel && $this->page == 1 && (sprintf("%0.4f", $this->y) == sprintf("%0.4f", $this->tMargin)))) {
10084 $this->page++;
10085 $this->pages[$this->page] = '';
10086 }
10087 $this->state = 2;
10088 $resetHTMLHeadersrequired = false;
10089
10090 if ($newformat) {
10091 $this->_setPageSize($newformat, $orientation);
10092 }
10093
10094 /* -- CSS-PAGE -- */
10095 // Paged media (page-box)
10096 if ($pagesel || (isset($this->page_box['using']) && $this->page_box['using'])) {
10097
10098 if ($pagesel || $this->page == 1) {
10099 $first = true;
10100 } else {
10101 $first = false;
10102 }
10103
10104 if ($this->mirrorMargins && ($this->page % 2 == 0)) {
10105 $oddEven = 'E';
10106 } else {
10107 $oddEven = 'O';
10108 }
10109
10110 if ($pagesel) {
10111 $psel = $pagesel;
10112 } elseif ($this->page_box['current']) {
10113 $psel = $this->page_box['current'];
10114 } else {
10115 $psel = '';
10116 }
10117
10118 list($orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS($psel, $first, $oddEven);
10119
10120 if ($this->mirrorMargins && ($this->page % 2 == 0)) {
10121
10122 if ($hname) {
10123 $ehvalue = 1;
10124 $ehname = $hname;
10125 } else {
10126 $ehvalue = -1;
10127 }
10128
10129 if ($fname) {
10130 $efvalue = 1;
10131 $efname = $fname;
10132 } else {
10133 $efvalue = -1;
10134 }
10135
10136 } else {
10137
10138 if ($hname) {
10139 $ohvalue = 1;
10140 $ohname = $hname;
10141 } else {
10142 $ohvalue = -1;
10143 }
10144
10145 if ($fname) {
10146 $ofvalue = 1;
10147 $ofname = $fname;
10148 } else {
10149 $ofvalue = -1;
10150 }
10151 }
10152
10153 if ($resetpagenum || $pagenumstyle || $suppress) {
10154 $this->PageNumSubstitutions[] = ['from' => ($this->page), 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress];
10155 }
10156
10157 // PAGED MEDIA - CROP / CROSS MARKS from @PAGE
10158 $this->show_marks = $marks;
10159
10160 // Background color
10161 if (isset($bg['BACKGROUND-COLOR'])) {
10162 $cor = $this->colorConverter->convert($bg['BACKGROUND-COLOR'], $this->PDFAXwarnings);
10163 if ($cor) {
10164 $this->bodyBackgroundColor = $cor;
10165 }
10166 } else {
10167 $this->bodyBackgroundColor = false;
10168 }
10169
10170 /* -- BACKGROUNDS -- */
10171 if (isset($bg['BACKGROUND-GRADIENT'])) {
10172 $this->bodyBackgroundGradient = $bg['BACKGROUND-GRADIENT'];
10173 } else {
10174 $this->bodyBackgroundGradient = false;
10175 }
10176
10177 // Tiling Patterns
10178 if (isset($bg['BACKGROUND-IMAGE']) && $bg['BACKGROUND-IMAGE']) {
10179 $ret = $this->SetBackground($bg, $this->pgwidth);
10180 if ($ret) {
10181 $this->bodyBackgroundImage = $ret;
10182 }
10183 } else {
10184 $this->bodyBackgroundImage = false;
10185 }
10186 /* -- END BACKGROUNDS -- */
10187
10188 $this->page_box['current'] = $psel;
10189 $this->page_box['using'] = true;
10190 }
10191 /* -- END CSS-PAGE -- */
10192
10193 // Page orientation
10194 if (!$orientation) {
10195 $orientation = $this->DefOrientation;
10196 } else {
10197 $orientation = strtoupper(substr($orientation, 0, 1));
10198 if ($orientation != $this->DefOrientation) {
10199 $this->OrientationChanges[$this->page] = true;
10200 }
10201 }
10202
10203 if ($orientation != $this->CurOrientation || $newformat) {
10204
10205 // Change orientation
10206 if ($orientation == 'P') {
10207 $this->wPt = $this->fwPt;
10208 $this->hPt = $this->fhPt;
10209 $this->w = $this->fw;
10210 $this->h = $this->fh;
10211 if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P') {
10212 $this->tMargin = $this->orig_tMargin;
10213 $this->bMargin = $this->orig_bMargin;
10214 $this->DeflMargin = $this->orig_lMargin;
10215 $this->DefrMargin = $this->orig_rMargin;
10216 $this->margin_header = $this->orig_hMargin;
10217 $this->margin_footer = $this->orig_fMargin;
10218 } else {
10219 $resetHTMLHeadersrequired = true;
10220 }
10221 } else {
10222 $this->wPt = $this->fhPt;
10223 $this->hPt = $this->fwPt;
10224 $this->w = $this->fh;
10225 $this->h = $this->fw;
10226
10227 if (($this->forcePortraitHeaders || $this->forcePortraitMargins) && $this->DefOrientation == 'P') {
10228 $this->tMargin = $this->orig_lMargin;
10229 $this->bMargin = $this->orig_rMargin;
10230 $this->DeflMargin = $this->orig_bMargin;
10231 $this->DefrMargin = $this->orig_tMargin;
10232 $this->margin_header = $this->orig_hMargin;
10233 $this->margin_footer = $this->orig_fMargin;
10234 } else {
10235 $resetHTMLHeadersrequired = true;
10236 }
10237 }
10238
10239 $this->CurOrientation = $orientation;
10240 $this->ResetMargins();
10241 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
10242 $this->PageBreakTrigger = $this->h - $this->bMargin;
10243 }
10244
10245 $this->pageDim[$this->page]['w'] = $this->w;
10246 $this->pageDim[$this->page]['h'] = $this->h;
10247
10248 $this->pageDim[$this->page]['outer_width_LR'] = isset($this->page_box['outer_width_LR']) ? $this->page_box['outer_width_LR'] : 0;
10249 $this->pageDim[$this->page]['outer_width_TB'] = isset($this->page_box['outer_width_TB']) ? $this->page_box['outer_width_TB'] : 0;
10250
10251 if (!isset($this->page_box['outer_width_LR']) && !isset($this->page_box['outer_width_TB'])) {
10252 $this->pageDim[$this->page]['bleedMargin'] = 0;
10253 } elseif ($this->bleedMargin <= $this->page_box['outer_width_LR'] && $this->bleedMargin <= $this->page_box['outer_width_TB']) {
10254 $this->pageDim[$this->page]['bleedMargin'] = $this->bleedMargin;
10255 } else {
10256 $this->pageDim[$this->page]['bleedMargin'] = min($this->page_box['outer_width_LR'], $this->page_box['outer_width_TB']) - 0.01;
10257 }
10258
10259 // If Page Margins are re-defined
10260 // strlen()>0 is used to pick up (integer) 0, (string) '0', or set value
10261 if ((strlen($mgl) > 0 && $this->DeflMargin != $mgl) || (strlen($mgr) > 0 && $this->DefrMargin != $mgr) || (strlen($mgt) > 0 && $this->tMargin != $mgt) || (strlen($mgb) > 0 && $this->bMargin != $mgb) || (strlen($mgh) > 0 && $this->margin_header != $mgh) || (strlen($mgf) > 0 && $this->margin_footer != $mgf)) {
10262
10263 if (strlen($mgl) > 0) {
10264 $this->DeflMargin = $mgl;
10265 }
10266
10267 if (strlen($mgr) > 0) {
10268 $this->DefrMargin = $mgr;
10269 }
10270
10271 if (strlen($mgt) > 0) {
10272 $this->tMargin = $mgt;
10273 }
10274
10275 if (strlen($mgb) > 0) {
10276 $this->bMargin = $mgb;
10277 }
10278
10279 if (strlen($mgh) > 0) {
10280 $this->margin_header = $mgh;
10281 }
10282
10283 if (strlen($mgf) > 0) {
10284 $this->margin_footer = $mgf;
10285 }
10286
10287 $this->ResetMargins();
10288 $this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);
10289
10290 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
10291 $resetHTMLHeadersrequired = true;
10292 }
10293
10294 $this->ResetMargins();
10295 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
10296 $this->SetAutoPageBreak($this->autoPageBreak, $this->bMargin);
10297
10298 // Reset column top margin
10299 $this->y0 = $this->tMargin;
10300
10301 $this->x = $this->lMargin;
10302 $this->y = $this->tMargin;
10303 $this->FontFamily = '';
10304
10305 // HEADERS AND FOOTERS // mPDF 6
10306 if ($ohvalue < 0 || strtoupper($ohvalue) == 'OFF') {
10307 $this->HTMLHeader = '';
10308 $resetHTMLHeadersrequired = true;
10309 } elseif ($ohname && $ohvalue > 0) {
10310 if (preg_match('/^html_(.*)$/i', $ohname, $n)) {
10311 $name = $n[1];
10312 } else {
10313 $name = $ohname;
10314 }
10315 if (isset($this->pageHTMLheaders[$name])) {
10316 $this->HTMLHeader = $this->pageHTMLheaders[$name];
10317 } else {
10318 $this->HTMLHeader = '';
10319 }
10320 $resetHTMLHeadersrequired = true;
10321 }
10322
10323 if ($ehvalue < 0 || strtoupper($ehvalue) == 'OFF') {
10324 $this->HTMLHeaderE = '';
10325 $resetHTMLHeadersrequired = true;
10326 } elseif ($ehname && $ehvalue > 0) {
10327 if (preg_match('/^html_(.*)$/i', $ehname, $n)) {
10328 $name = $n[1];
10329 } else {
10330 $name = $ehname;
10331 }
10332 if (isset($this->pageHTMLheaders[$name])) {
10333 $this->HTMLHeaderE = $this->pageHTMLheaders[$name];
10334 } else {
10335 $this->HTMLHeaderE = '';
10336 }
10337 $resetHTMLHeadersrequired = true;
10338 }
10339
10340 if ($ofvalue < 0 || strtoupper($ofvalue) == 'OFF') {
10341 $this->HTMLFooter = '';
10342 $resetHTMLHeadersrequired = true;
10343 } elseif ($ofname && $ofvalue > 0) {
10344 if (preg_match('/^html_(.*)$/i', $ofname, $n)) {
10345 $name = $n[1];
10346 } else {
10347 $name = $ofname;
10348 }
10349 if (isset($this->pageHTMLfooters[$name])) {
10350 $this->HTMLFooter = $this->pageHTMLfooters[$name];
10351 } else {
10352 $this->HTMLFooter = '';
10353 }
10354 $resetHTMLHeadersrequired = true;
10355 }
10356
10357 if ($efvalue < 0 || strtoupper($efvalue) == 'OFF') {
10358 $this->HTMLFooterE = '';
10359 $resetHTMLHeadersrequired = true;
10360 } elseif ($efname && $efvalue > 0) {
10361 if (preg_match('/^html_(.*)$/i', $efname, $n)) {
10362 $name = $n[1];
10363 } else {
10364 $name = $efname;
10365 }
10366 if (isset($this->pageHTMLfooters[$name])) {
10367 $this->HTMLFooterE = $this->pageHTMLfooters[$name];
10368 } else {
10369 $this->HTMLFooterE = '';
10370 }
10371 $resetHTMLHeadersrequired = true;
10372 }
10373
10374 if ($resetHTMLHeadersrequired) {
10375 $this->SetHTMLHeader($this->HTMLHeader);
10376 $this->SetHTMLHeader($this->HTMLHeaderE, 'E');
10377 $this->SetHTMLFooter($this->HTMLFooter);
10378 $this->SetHTMLFooter($this->HTMLFooterE, 'E');
10379 }
10380
10381
10382 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
10383 $this->_setAutoHeaderHeight($this->HTMLHeaderE);
10384 $this->_setAutoFooterHeight($this->HTMLFooterE);
10385 } else { // ODD or DEFAULT
10386 $this->_setAutoHeaderHeight($this->HTMLHeader);
10387 $this->_setAutoFooterHeight($this->HTMLFooter);
10388 }
10389
10390 // Reset column top margin
10391 $this->y0 = $this->tMargin;
10392
10393 $this->x = $this->lMargin;
10394 $this->y = $this->tMargin;
10395 }
10396
10397 // mPDF 6
10398 function _setAutoHeaderHeight(&$htmlh)
10399 {
10400 /* When the setAutoTopMargin option is set to pad/stretch, only apply auto header height when a header exists */
10401 if ($this->HTMLHeader === '' && $this->HTMLHeaderE === '') {
10402 return;
10403 }
10404
10405 if ($this->setAutoTopMargin == 'pad') {
10406 if (isset($htmlh['h']) && $htmlh['h']) {
10407 $h = $htmlh['h'];
10408 } // 5.7.3
10409 else {
10410 $h = 0;
10411 }
10412 $this->tMargin = $this->margin_header + $h + $this->orig_tMargin;
10413 } elseif ($this->setAutoTopMargin == 'stretch') {
10414 if (isset($htmlh['h']) && $htmlh['h']) {
10415 $h = $htmlh['h'];
10416 } // 5.7.3
10417 else {
10418 $h = 0;
10419 }
10420 $this->tMargin = max($this->orig_tMargin, $this->margin_header + $h + $this->autoMarginPadding);
10421 }
10422 }
10423
10424 // mPDF 6
10425 function _setAutoFooterHeight(&$htmlf)
10426 {
10427 /* When the setAutoTopMargin option is set to pad/stretch, only apply auto footer height when a footer exists */
10428 if ($this->HTMLFooter === '' && $this->HTMLFooterE === '') {
10429 return;
10430 }
10431
10432 if ($this->setAutoBottomMargin == 'pad') {
10433 if (isset($htmlf['h']) && $htmlf['h']) {
10434 $h = $htmlf['h'];
10435 } // 5.7.3
10436 else {
10437 $h = 0;
10438 }
10439 $this->bMargin = $this->margin_footer + $h + $this->orig_bMargin;
10440 $this->PageBreakTrigger = $this->h - $this->bMargin;
10441 } elseif ($this->setAutoBottomMargin == 'stretch') {
10442 if (isset($htmlf['h']) && $htmlf['h']) {
10443 $h = $htmlf['h'];
10444 } // 5.7.3
10445 else {
10446 $h = 0;
10447 }
10448 $this->bMargin = max($this->orig_bMargin, $this->margin_footer + $h + $this->autoMarginPadding);
10449 $this->PageBreakTrigger = $this->h - $this->bMargin;
10450 }
10451 }
10452
10453 function _endpage()
10454 {
10455 /* -- CSS-IMAGE-FLOAT -- */
10456 $this->printfloatbuffer();
10457 /* -- END CSS-IMAGE-FLOAT -- */
10458
10459 if ($this->visibility != 'visible') {
10460 $this->SetVisibility('visible');
10461 }
10462 $this->EndLayer();
10463 // End of page contents
10464 $this->state = 1;
10465 }
10466
10467 function _dounderline($x, $y, $txt, $OTLdata = false, $textvar = 0)
10468 {
10469 // Now print line exactly where $y secifies - called from Text() and Cell() - adjust position there
10470 // WORD SPACING
10471 $w = ($this->GetStringWidth($txt, false, $OTLdata, $textvar) * Mpdf::SCALE) + ($this->charspacing * mb_strlen($txt, $this->mb_enc)) + ( $this->ws * mb_substr_count($txt, ' ', $this->mb_enc));
10472 // Draw a line
10473 return sprintf('%.3F %.3F m %.3F %.3F l S', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, ($x * Mpdf::SCALE) + $w, ($this->h - $y) * Mpdf::SCALE);
10474 }
10475
10476
10477
10478 /* -- WATERMARK -- */
10479
10480 // add a watermark
10481 function watermark($texte, $angle = 45, $fontsize = 96, $alpha = 0.2)
10482 {
10483 if ($this->PDFA || $this->PDFX) {
10484 throw new \Mpdf\MpdfException('PDFA and PDFX do not permit transparency, so mPDF does not allow Watermarks!');
10485 }
10486
10487 if (!$this->watermark_font) {
10488 $this->watermark_font = $this->default_font;
10489 }
10490
10491 $this->SetFont($this->watermark_font, "B", $fontsize, false); // Don't output
10492 $texte = $this->purify_utf8_text($texte);
10493
10494 if ($this->text_input_as_HTML) {
10495 $texte = $this->all_entities_to_utf8($texte);
10496 }
10497
10498 if ($this->usingCoreFont) {
10499 $texte = mb_convert_encoding($texte, $this->mb_enc, 'UTF-8');
10500 }
10501
10502 // DIRECTIONALITY
10503 if (preg_match("/([" . $this->pregRTLchars . "])/u", $texte)) {
10504 $this->biDirectional = true;
10505 } // *OTL*
10506
10507 $textvar = 0;
10508 $save_OTLtags = $this->OTLtags;
10509 $this->OTLtags = [];
10510 if ($this->useKerning) {
10511 if ($this->CurrentFont['haskernGPOS']) {
10512 $this->OTLtags['Plus'] .= ' kern';
10513 } else {
10514 $textvar = ($textvar | TextVars::FC_KERNING);
10515 }
10516 }
10517
10518 /* -- OTL -- */
10519 // Use OTL OpenType Table Layout - GSUB & GPOS
10520 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
10521 $texte = $this->otl->applyOTL($texte, $this->CurrentFont['useOTL']);
10522 $OTLdata = $this->otl->OTLdata;
10523 }
10524 /* -- END OTL -- */
10525 $this->OTLtags = $save_OTLtags;
10526
10527 $this->magic_reverse_dir($texte, $this->directionality, $OTLdata);
10528
10529 $this->SetAlpha($alpha);
10530
10531 $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
10532
10533 $szfont = $fontsize;
10534 $loop = 0;
10535 $maxlen = (min($this->w, $this->h) ); // sets max length of text as 7/8 width/height of page
10536
10537 while ($loop == 0) {
10538 $this->SetFont($this->watermark_font, "B", $szfont, false); // Don't output
10539 $offset = ((sin(deg2rad($angle))) * ($szfont / Mpdf::SCALE));
10540
10541 $strlen = $this->GetStringWidth($texte, true, $OTLdata, $textvar);
10542 if ($strlen > $maxlen - $offset) {
10543 $szfont --;
10544 } else {
10545 $loop ++;
10546 }
10547 }
10548
10549 $this->SetFont($this->watermark_font, "B", $szfont - 0.1, true, true); // Output The -0.1 is because SetFont above is not written to PDF
10550
10551 // Repeating it will not output anything as mPDF thinks it is set
10552 $adj = ((cos(deg2rad($angle))) * ($strlen / 2));
10553 $opp = ((sin(deg2rad($angle))) * ($strlen / 2));
10554
10555 $wx = ($this->w / 2) - $adj + $offset / 3;
10556 $wy = ($this->h / 2) + $opp;
10557
10558 $this->Rotate($angle, $wx, $wy);
10559 $this->Text($wx, $wy, $texte, $OTLdata, $textvar);
10560 $this->Rotate(0);
10561 $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
10562
10563 $this->SetAlpha(1);
10564 }
10565
10566 function watermarkImg($src, $alpha = 0.2)
10567 {
10568 if ($this->PDFA || $this->PDFX) {
10569 throw new \Mpdf\MpdfException('PDFA and PDFX do not permit transparency, so mPDF does not allow Watermarks!');
10570 }
10571
10572 if ($this->watermarkImgBehind) {
10573 $this->watermarkImgAlpha = $this->SetAlpha($alpha, 'Normal', true);
10574 } else {
10575 $this->SetAlpha($alpha, $this->watermarkImgAlphaBlend);
10576 }
10577
10578 $this->Image($src, 0, 0, 0, 0, '', '', true, true, true);
10579
10580 if (!$this->watermarkImgBehind) {
10581 $this->SetAlpha(1);
10582 }
10583 }
10584
10585 /* -- END WATERMARK -- */
10586
10587 function Rotate($angle, $x = -1, $y = -1)
10588 {
10589 if ($x == -1) {
10590 $x = $this->x;
10591 }
10592 if ($y == -1) {
10593 $y = $this->y;
10594 }
10595 if ($this->angle != 0) {
10596 $this->writer->write('Q');
10597 }
10598 $this->angle = $angle;
10599 if ($angle != 0) {
10600 $angle*=M_PI / 180;
10601 $c = cos($angle);
10602 $s = sin($angle);
10603 $cx = $x * Mpdf::SCALE;
10604 $cy = ($this->h - $y) * Mpdf::SCALE;
10605 $this->writer->write(sprintf('q %.5F %.5F %.5F %.5F %.3F %.3F cm 1 0 0 1 %.3F %.3F cm', $c, $s, -$s, $c, $cx, $cy, -$cx, -$cy));
10606 }
10607 }
10608
10609 function CircularText($x, $y, $r, $text, $align = 'top', $fontfamily = '', $fontsize = 0, $fontstyle = '', $kerning = 120, $fontwidth = 100, $divider = '')
10610 {
10611 if (empty($this->directWrite)) {
10612 $this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
10613 }
10614
10615 $this->directWrite->CircularText($x, $y, $r, $text, $align, $fontfamily, $fontsize, $fontstyle, $kerning, $fontwidth, $divider);
10616 }
10617
10618 // From Invoice
10619 function RoundedRect($x, $y, $w, $h, $r, $style = '')
10620 {
10621 $hp = $this->h;
10622
10623 if ($style == 'F') {
10624 $op = 'f';
10625 } elseif ($style == 'FD' or $style == 'DF') {
10626 $op = 'B';
10627 } else {
10628 $op = 'S';
10629 }
10630
10631 $MyArc = 4 / 3 * (sqrt(2) - 1);
10632 $this->writer->write(sprintf('%.3F %.3F m', ($x + $r) * Mpdf::SCALE, ($hp - $y) * Mpdf::SCALE));
10633 $xc = $x + $w - $r;
10634 $yc = $y + $r;
10635 $this->writer->write(sprintf('%.3F %.3F l', $xc * Mpdf::SCALE, ($hp - $y) * Mpdf::SCALE));
10636
10637 $this->_Arc($xc + $r * $MyArc, $yc - $r, $xc + $r, $yc - $r * $MyArc, $xc + $r, $yc);
10638 $xc = $x + $w - $r;
10639 $yc = $y + $h - $r;
10640 $this->writer->write(sprintf('%.3F %.3F l', ($x + $w) * Mpdf::SCALE, ($hp - $yc) * Mpdf::SCALE));
10641
10642 $this->_Arc($xc + $r, $yc + $r * $MyArc, $xc + $r * $MyArc, $yc + $r, $xc, $yc + $r);
10643 $xc = $x + $r;
10644 $yc = $y + $h - $r;
10645 $this->writer->write(sprintf('%.3F %.3F l', $xc * Mpdf::SCALE, ($hp - ($y + $h)) * Mpdf::SCALE));
10646
10647 $this->_Arc($xc - $r * $MyArc, $yc + $r, $xc - $r, $yc + $r * $MyArc, $xc - $r, $yc);
10648 $xc = $x + $r;
10649 $yc = $y + $r;
10650 $this->writer->write(sprintf('%.3F %.3F l', ($x) * Mpdf::SCALE, ($hp - $yc) * Mpdf::SCALE));
10651
10652 $this->_Arc($xc - $r, $yc - $r * $MyArc, $xc - $r * $MyArc, $yc - $r, $xc, $yc - $r);
10653 $this->writer->write($op);
10654 }
10655
10656 function _Arc($x1, $y1, $x2, $y2, $x3, $y3)
10657 {
10658 $h = $this->h;
10659 $this->writer->write(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', $x1 * Mpdf::SCALE, ($h - $y1) * Mpdf::SCALE, $x2 * Mpdf::SCALE, ($h - $y2) * Mpdf::SCALE, $x3 * Mpdf::SCALE, ($h - $y3) * Mpdf::SCALE));
10660 }
10661
10662 // ====================================================
10663
10664
10665
10666 /* -- DIRECTW -- */
10667 function Shaded_box($text, $font = '', $fontstyle = 'B', $szfont = '', $width = '70%', $style = 'DF', $radius = 2.5, $fill = '#FFFFFF', $color = '#000000', $pad = 2)
10668 {
10669 // F (shading - no line),S (line, no shading),DF (both)
10670 if (empty($this->directWrite)) {
10671 $this->directWrite = new DirectWrite($this, $this->otl, $this->sizeConverter, $this->colorConverter);
10672 }
10673 $this->directWrite->Shaded_box($text, $font, $fontstyle, $szfont, $width, $style, $radius, $fill, $color, $pad);
10674 }
10675
10676 /* -- END DIRECTW -- */
10677
10678 function UTF8StringToArray($str, $addSubset = true)
10679 {
10680 $out = [];
10681 $len = strlen($str);
10682 for ($i = 0; $i < $len; $i++) {
10683 $uni = -1;
10684 $h = ord($str[$i]);
10685 if ($h <= 0x7F) {
10686 $uni = $h;
10687 } elseif ($h >= 0xC2) {
10688 if (($h <= 0xDF) && ($i < $len - 1)) {
10689 $uni = ($h & 0x1F) << 6 | (ord($str[++$i]) & 0x3F);
10690 } elseif (($h <= 0xEF) && ($i < $len - 2)) {
10691 $uni = ($h & 0x0F) << 12 | (ord($str[++$i]) & 0x3F) << 6 | (ord($str[++$i]) & 0x3F);
10692 } elseif (($h <= 0xF4) && ($i < $len - 3)) {
10693 $uni = ($h & 0x0F) << 18 | (ord($str[++$i]) & 0x3F) << 12 | (ord($str[++$i]) & 0x3F) << 6 | (ord($str[++$i]) & 0x3F);
10694 }
10695 }
10696 if ($uni >= 0) {
10697 $out[] = $uni;
10698 if ($addSubset && isset($this->CurrentFont['subset'])) {
10699 $this->CurrentFont['subset'][$uni] = $uni;
10700 }
10701 }
10702 }
10703 return $out;
10704 }
10705
10706 // Convert utf-8 string to <HHHHHH> for Font Subsets
10707 function UTF8toSubset($str)
10708 {
10709 $ret = '<';
10710 // $str = preg_replace('/'.preg_quote($this->aliasNbPg,'/').'/', chr(7), $str ); // mPDF 6 deleted
10711 // $str = preg_replace('/'.preg_quote($this->aliasNbPgGp,'/').'/', chr(8), $str ); // mPDF 6 deleted
10712 $unicode = $this->UTF8StringToArray($str);
10713 $orig_fid = $this->CurrentFont['subsetfontids'][0];
10714 $last_fid = $this->CurrentFont['subsetfontids'][0];
10715 foreach ($unicode as $c) {
10716 /* // mPDF 6 deleted
10717 if ($c == 7 || $c == 8) {
10718 if ($orig_fid != $last_fid) {
10719 $ret .= '> Tj /F'.$orig_fid.' '.$this->FontSizePt.' Tf <';
10720 $last_fid = $orig_fid;
10721 }
10722 if ($c == 7) { $ret .= $this->aliasNbPgHex; }
10723 else { $ret .= $this->aliasNbPgGpHex; }
10724 continue;
10725 }
10726 */
10727 if (!$this->_charDefined($this->CurrentFont['cw'], $c)) {
10728 $c = 0;
10729 } // mPDF 6
10730 for ($i = 0; $i < 99; $i++) {
10731 // return c as decimal char
10732 $init = array_search($c, $this->CurrentFont['subsets'][$i]);
10733 if ($init !== false) {
10734 if ($this->CurrentFont['subsetfontids'][$i] != $last_fid) {
10735 $ret .= '> Tj /F' . $this->CurrentFont['subsetfontids'][$i] . ' ' . $this->FontSizePt . ' Tf <';
10736 $last_fid = $this->CurrentFont['subsetfontids'][$i];
10737 }
10738 $ret .= sprintf("%02s", strtoupper(dechex($init)));
10739 break;
10740 } // TrueType embedded SUBSETS
10741 elseif (count($this->CurrentFont['subsets'][$i]) < 255) {
10742 $n = count($this->CurrentFont['subsets'][$i]);
10743 $this->CurrentFont['subsets'][$i][$n] = $c;
10744 if ($this->CurrentFont['subsetfontids'][$i] != $last_fid) {
10745 $ret .= '> Tj /F' . $this->CurrentFont['subsetfontids'][$i] . ' ' . $this->FontSizePt . ' Tf <';
10746 $last_fid = $this->CurrentFont['subsetfontids'][$i];
10747 }
10748 $ret .= sprintf("%02s", strtoupper(dechex($n)));
10749 break;
10750 } elseif (!isset($this->CurrentFont['subsets'][($i + 1)])) {
10751 // TrueType embedded SUBSETS
10752 $this->CurrentFont['subsets'][($i + 1)] = [0 => 0];
10753 $new_fid = count($this->fonts) + $this->extraFontSubsets + 1;
10754 $this->CurrentFont['subsetfontids'][($i + 1)] = $new_fid;
10755 $this->extraFontSubsets++;
10756 }
10757 }
10758 }
10759 $ret .= '>';
10760 if ($last_fid != $orig_fid) {
10761 $ret .= ' Tj /F' . $orig_fid . ' ' . $this->FontSizePt . ' Tf <> ';
10762 }
10763 return $ret;
10764 }
10765
10766 /* -- CJK-FONTS -- */
10767
10768 // from class PDF_Chinese CJK EXTENSIONS
10769 function AddCIDFont($family, $style, $name, &$cw, $CMap, $registry, $desc)
10770 {
10771 $fontkey = strtolower($family) . strtoupper($style);
10772 if (isset($this->fonts[$fontkey])) {
10773 throw new \Mpdf\MpdfException("Font already added: $family $style");
10774 }
10775 $i = count($this->fonts) + $this->extraFontSubsets + 1;
10776 $name = str_replace(' ', '', $name);
10777 if ($family == 'sjis') {
10778 $up = -120;
10779 } else {
10780 $up = -130;
10781 }
10782 // ? 'up' and 'ut' do not seem to be referenced anywhere
10783 $this->fonts[$fontkey] = ['i' => $i, 'type' => 'Type0', 'name' => $name, 'up' => $up, 'ut' => 40, 'cw' => $cw, 'CMap' => $CMap, 'registry' => $registry, 'MissingWidth' => 1000, 'desc' => $desc];
10784 }
10785
10786 function AddCJKFont($family)
10787 {
10788
10789 if ($this->PDFA || $this->PDFX) {
10790 throw new \Mpdf\MpdfException("Adobe CJK fonts cannot be embedded in mPDF (required for PDFA1-b and PDFX/1-a).");
10791 }
10792 if ($family == 'big5') {
10793 $this->AddBig5Font();
10794 } elseif ($family == 'gb') {
10795 $this->AddGBFont();
10796 } elseif ($family == 'sjis') {
10797 $this->AddSJISFont();
10798 } elseif ($family == 'uhc') {
10799 $this->AddUHCFont();
10800 }
10801 }
10802
10803 function AddBig5Font()
10804 {
10805 // Add Big5 font with proportional Latin
10806 $family = 'big5';
10807 $name = 'MSungStd-Light-Acro';
10808 $cw = $this->Big5_widths;
10809 $CMap = 'UniCNS-UTF16-H';
10810 $registry = ['ordering' => 'CNS1', 'supplement' => 4];
10811 $desc = [
10812 'Ascent' => 880,
10813 'Descent' => -120,
10814 'CapHeight' => 880,
10815 'Flags' => 6,
10816 'FontBBox' => '[-160 -249 1015 1071]',
10817 'ItalicAngle' => 0,
10818 'StemV' => 93,
10819 ];
10820 $this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
10821 $this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
10822 $this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
10823 $this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
10824 }
10825
10826 function AddGBFont()
10827 {
10828 // Add GB font with proportional Latin
10829 $family = 'gb';
10830 $name = 'STSongStd-Light-Acro';
10831 $cw = $this->GB_widths;
10832 $CMap = 'UniGB-UTF16-H';
10833 $registry = ['ordering' => 'GB1', 'supplement' => 4];
10834 $desc = [
10835 'Ascent' => 880,
10836 'Descent' => -120,
10837 'CapHeight' => 737,
10838 'Flags' => 6,
10839 'FontBBox' => '[-25 -254 1000 880]',
10840 'ItalicAngle' => 0,
10841 'StemV' => 58,
10842 'Style' => '<< /Panose <000000000400000000000000> >>',
10843 ];
10844 $this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
10845 $this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
10846 $this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
10847 $this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
10848 }
10849
10850 function AddSJISFont()
10851 {
10852 // Add SJIS font with proportional Latin
10853 $family = 'sjis';
10854 $name = 'KozMinPro-Regular-Acro';
10855 $cw = $this->SJIS_widths;
10856 $CMap = 'UniJIS-UTF16-H';
10857 $registry = ['ordering' => 'Japan1', 'supplement' => 5];
10858 $desc = [
10859 'Ascent' => 880,
10860 'Descent' => -120,
10861 'CapHeight' => 740,
10862 'Flags' => 6,
10863 'FontBBox' => '[-195 -272 1110 1075]',
10864 'ItalicAngle' => 0,
10865 'StemV' => 86,
10866 'XHeight' => 502,
10867 ];
10868 $this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
10869 $this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
10870 $this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
10871 $this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
10872 }
10873
10874 function AddUHCFont()
10875 {
10876 // Add UHC font with proportional Latin
10877 $family = 'uhc';
10878 $name = 'HYSMyeongJoStd-Medium-Acro';
10879 $cw = $this->UHC_widths;
10880 $CMap = 'UniKS-UTF16-H';
10881 $registry = ['ordering' => 'Korea1', 'supplement' => 2];
10882 $desc = [
10883 'Ascent' => 880,
10884 'Descent' => -120,
10885 'CapHeight' => 720,
10886 'Flags' => 6,
10887 'FontBBox' => '[-28 -148 1001 880]',
10888 'ItalicAngle' => 0,
10889 'StemV' => 60,
10890 'Style' => '<< /Panose <000000000600000000000000> >>',
10891 ];
10892 $this->AddCIDFont($family, '', $name, $cw, $CMap, $registry, $desc);
10893 $this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry, $desc);
10894 $this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry, $desc);
10895 $this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry, $desc);
10896 }
10897
10898 /* -- END CJK-FONTS -- */
10899
10907
10908 function SetDefaultFont($font)
10909 {
10910 // Disallow embedded fonts to be used as defaults in PDFA
10911 if ($this->PDFA || $this->PDFX) {
10912 if (strtolower($font) == 'ctimes') {
10913 $font = 'serif';
10914 }
10915 if (strtolower($font) == 'ccourier') {
10916 $font = 'monospace';
10917 }
10918 if (strtolower($font) == 'chelvetica') {
10919 $font = 'sans-serif';
10920 }
10921 }
10922 $font = $this->SetFont($font); // returns substituted font if necessary
10923 $this->default_font = $font;
10924 $this->original_default_font = $font;
10925 if (!$this->watermark_font) {
10926 $this->watermark_font = $font;
10927 } // *WATERMARK*
10928 $this->defaultCSS['BODY']['FONT-FAMILY'] = $font;
10929 $this->cssManager->CSS['BODY']['FONT-FAMILY'] = $font;
10930 }
10931
10932 function SetDefaultFontSize($fontsize)
10933 {
10934 $this->default_font_size = $fontsize;
10935 $this->original_default_font_size = $fontsize;
10936 $this->SetFontSize($fontsize);
10937 $this->defaultCSS['BODY']['FONT-SIZE'] = $fontsize . 'pt';
10938 $this->cssManager->CSS['BODY']['FONT-SIZE'] = $fontsize . 'pt';
10939 }
10940
10941 function SetDefaultBodyCSS($prop, $val)
10942 {
10943 if ($prop) {
10944 $this->defaultCSS['BODY'][strtoupper($prop)] = $val;
10945 $this->cssManager->CSS['BODY'][strtoupper($prop)] = $val;
10946 }
10947 }
10948
10949 function SetDirectionality($dir = 'ltr')
10950 {
10951 /* -- OTL -- */
10952 if (strtolower($dir) == 'rtl') {
10953 if ($this->directionality != 'rtl') {
10954 // Swop L/R Margins so page 1 RTL is an 'even' page
10955 $tmp = $this->DeflMargin;
10956 $this->DeflMargin = $this->DefrMargin;
10957 $this->DefrMargin = $tmp;
10958 $this->orig_lMargin = $this->DeflMargin;
10959 $this->orig_rMargin = $this->DefrMargin;
10960
10961 $this->SetMargins($this->DeflMargin, $this->DefrMargin, $this->tMargin);
10962 }
10963 $this->directionality = 'rtl';
10964 $this->defaultAlign = 'R';
10965 $this->defaultTableAlign = 'R';
10966 } else {
10967 /* -- END OTL -- */
10968 $this->directionality = 'ltr';
10969 $this->defaultAlign = 'L';
10970 $this->defaultTableAlign = 'L';
10971 } // *OTL*
10972 $this->cssManager->CSS['BODY']['DIRECTION'] = $this->directionality;
10973 }
10974
10975 // Return either a number (factor) - based on current set fontsize (if % or em) - or exact lineheight (with 'mm' after it)
10976 function fixLineheight($v)
10977 {
10978 $lh = false;
10979 if (preg_match('/^[0-9\.,]*$/', $v) && $v >= 0) {
10980 return ($v + 0);
10981 } elseif (strtoupper($v) == 'NORMAL' || $v == 'N') {
10982 return 'N'; // mPDF 6
10983 } else {
10984 $tlh = $this->sizeConverter->convert($v, $this->FontSize, $this->FontSize, true);
10985 if ($tlh) {
10986 return ($tlh . 'mm');
10987 }
10988 }
10989 return $this->normalLineheight;
10990 }
10991
10992 function _getNormalLineheight($desc = false)
10993 {
10994 if (!$desc) {
10995 $desc = $this->CurrentFont['desc'];
10996 }
10997 if (!isset($desc['Leading'])) {
10998 $desc['Leading'] = 0;
10999 }
11000 if ($this->useFixedNormalLineHeight) {
11001 $lh = $this->normalLineheight;
11002 } elseif (isset($desc['Ascent']) && $desc['Ascent']) {
11003 $lh = ($this->adjustFontDescLineheight * ($desc['Ascent'] - $desc['Descent'] + $desc['Leading']) / 1000);
11004 } else {
11005 $lh = $this->normalLineheight;
11006 }
11007 return $lh;
11008 }
11009
11010 // Set a (fixed) lineheight to an actual value - either to named fontsize(pts) or default
11011 function SetLineHeight($FontPt = '', $lh = '')
11012 {
11013 if (!$FontPt) {
11014 $FontPt = $this->FontSizePt;
11015 }
11016 $fs = $FontPt / Mpdf::SCALE;
11017 $this->lineheight = $this->_computeLineheight($lh, $fs);
11018 }
11019
11020 function _computeLineheight($lh, $fs = '')
11021 {
11022 if ($this->shrin_k > 1) {
11023 $k = $this->shrin_k;
11024 } else {
11025 $k = 1;
11026 }
11027 if (!$fs) {
11028 $fs = $this->FontSize;
11029 }
11030 if ($lh == 'N') {
11031 $lh = $this->_getNormalLineheight();
11032 }
11033 if (preg_match('/mm/', $lh)) {
11034 return (((float) $lh) / $k); // convert to number
11035 } elseif ($lh > 0) {
11036 return ($fs * $lh);
11037 }
11038 return ($fs * $this->normalLineheight);
11039 }
11040
11041 function _setLineYpos(&$fontsize, &$fontdesc, &$CSSlineheight, $blockYpos = false)
11042 {
11043 $ypos['glyphYorigin'] = 0;
11044 $ypos['baseline-shift'] = 0;
11045 $linegap = 0;
11046 $leading = 0;
11047
11048 if (isset($fontdesc['Ascent']) && $fontdesc['Ascent'] && !$this->useFixedTextBaseline) {
11049 // Fontsize uses font metrics - this method seems to produce results compatible with browsers (except IE9)
11050 $ypos['boxtop'] = $fontdesc['Ascent'] / 1000 * $fontsize;
11051 $ypos['boxbottom'] = $fontdesc['Descent'] / 1000 * $fontsize;
11052 if (isset($fontdesc['Leading'])) {
11053 $linegap = $fontdesc['Leading'] / 1000 * $fontsize;
11054 }
11055 } // Default if not set - uses baselineC
11056 else {
11057 $ypos['boxtop'] = (0.5 + $this->baselineC) * $fontsize;
11058 $ypos['boxbottom'] = -(0.5 - $this->baselineC) * $fontsize;
11059 }
11060 $fontheight = $ypos['boxtop'] - $ypos['boxbottom'];
11061
11062 if ($this->shrin_k > 1) {
11063 $shrin_k = $this->shrin_k;
11064 } else {
11065 $shrin_k = 1;
11066 }
11067
11068 $leading = 0;
11069 if ($CSSlineheight == 'N') {
11070 $lh = $this->_getNormalLineheight($fontdesc);
11071 $lineheight = ($fontsize * $lh);
11072 $leading += $linegap; // specified in hhea or sTypo in OpenType tables
11073 } elseif (preg_match('/mm/', $CSSlineheight)) {
11074 $lineheight = (((float) $CSSlineheight) / $shrin_k); // convert to number
11075 } // ??? If lineheight is a factor e.g. 1.3 ?? use factor x 1em or ? use 'normal' lineheight * factor
11076 // Could depend on value for $text_height - a draft CSS value as set above for now
11077 elseif ($CSSlineheight > 0) {
11078 $lineheight = ($fontsize * $CSSlineheight);
11079 } else {
11080 $lineheight = ($fontsize * $this->normalLineheight);
11081 }
11082
11083 // In general, calculate the "leading" - the difference between the fontheight and the lineheight
11084 // and add half to the top and half to the bottom. BUT
11085 // If an inline element has a font-size less than the block element, and the line-height is set as an em or % value
11086 // it will add too much leading below the font and expand the height of the line - so just use the block element exttop/extbottom:
11087 if (preg_match('/mm/', $CSSlineheight)
11088 && ($blockYpos && $ypos['boxtop'] < $blockYpos['boxtop'])
11089 && ($blockYpos && $ypos['boxbottom'] > $blockYpos['boxbottom'])) {
11090
11091 $ypos['exttop'] = $blockYpos['exttop'];
11092 $ypos['extbottom'] = $blockYpos['extbottom'];
11093
11094 } else {
11095
11096 $leading += ($lineheight - $fontheight);
11097
11098 $ypos['exttop'] = $ypos['boxtop'] + $leading / 2;
11099 $ypos['extbottom'] = $ypos['boxbottom'] - $leading / 2;
11100 }
11101
11102
11103 // TEMP ONLY FOR DEBUGGING *********************************
11104 // $ypos['lineheight'] = $lineheight;
11105 // $ypos['fontheight'] = $fontheight;
11106 // $ypos['leading'] = $leading;
11107
11108 return $ypos;
11109 }
11110
11111 /* Called from WriteFlowingBlock() and finishFlowingBlock()
11112 Determines the line hieght and glyph/writing position
11113 for each element in the line to be written */
11114
11115 function _setInlineBlockHeights(&$lineBox, &$stackHeight, &$content, &$font, $is_table)
11116 {
11117 if ($this->shrin_k > 1) {
11118 $shrin_k = $this->shrin_k;
11119 } else {
11120 $shrin_k = 1;
11121 }
11122
11123 $ypos = [];
11124 $bordypos = [];
11125 $bgypos = [];
11126
11127 if ($is_table) {
11128 // FOR TABLE
11129 $fontsize = $this->FontSize;
11130 $fontkey = $this->FontFamily . $this->FontStyle;
11131 $fontdesc = $this->fonts[$fontkey]['desc'];
11132 $CSSlineheight = $this->cellLineHeight;
11133 $line_stacking_strategy = $this->cellLineStackingStrategy; // inline-line-height [default] | block-line-height | max-height | grid-height
11134 $line_stacking_shift = $this->cellLineStackingShift; // consider-shifts [default] | disregard-shifts
11135 } else {
11136 // FOR BLOCK FONT
11137 $fontsize = $this->blk[$this->blklvl]['InlineProperties']['size'];
11138 $fontkey = $this->blk[$this->blklvl]['InlineProperties']['family'] . $this->blk[$this->blklvl]['InlineProperties']['style'];
11139 $fontdesc = $this->fonts[$fontkey]['desc'];
11140 $CSSlineheight = $this->blk[$this->blklvl]['line_height'];
11141 // inline-line-height | block-line-height | max-height | grid-height
11142 $line_stacking_strategy = (isset($this->blk[$this->blklvl]['line_stacking_strategy']) ? $this->blk[$this->blklvl]['line_stacking_strategy'] : 'inline-line-height');
11143 // consider-shifts | disregard-shifts
11144 $line_stacking_shift = (isset($this->blk[$this->blklvl]['line_stacking_shift']) ? $this->blk[$this->blklvl]['line_stacking_shift'] : 'consider-shifts');
11145 }
11146 $boxLineHeight = $this->_computeLineheight($CSSlineheight, $fontsize);
11147
11148
11149 // First, set a "strut" using block font at index $lineBox[-1]
11150 $ypos[-1] = $this->_setLineYpos($fontsize, $fontdesc, $CSSlineheight);
11151
11152 // for the block element - always taking the block EXTENDED progression including leading - which may be negative
11153 if ($line_stacking_strategy == 'block-line-height') {
11154 $topy = $ypos[-1]['exttop'];
11155 $bottomy = $ypos[-1]['extbottom'];
11156 } else {
11157 $topy = 0;
11158 $bottomy = 0;
11159 }
11160
11161 // Get text-middle for aligning images/objects
11162 $midpoint = $ypos[-1]['boxtop'] - (($ypos[-1]['boxtop'] - $ypos[-1]['boxbottom']) / 2);
11163
11164 // for images / inline objects / replaced elements
11165 $mta = 0; // Maximum top-aligned
11166 $mba = 0; // Maximum bottom-aligned
11167 foreach ($content as $k => $chunk) {
11168 if (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]['type'] == 'listmarker') {
11169 $ypos[$k] = $ypos[-1];
11170 // UPDATE Maximums
11171 if ($line_stacking_strategy == 'block-line-height' || $line_stacking_strategy == 'grid-height' || $line_stacking_strategy == 'max-height') { // don't include extended block progression of all inline elements
11172 if ($ypos[$k]['boxtop'] > $topy) {
11173 $topy = $ypos[$k]['boxtop'];
11174 }
11175 if ($ypos[$k]['boxbottom'] < $bottomy) {
11176 $bottomy = $ypos[$k]['boxbottom'];
11177 }
11178 } else {
11179 if ($ypos[$k]['exttop'] > $topy) {
11180 $topy = $ypos[$k]['exttop'];
11181 }
11182 if ($ypos[$k]['extbottom'] < $bottomy) {
11183 $bottomy = $ypos[$k]['extbottom'];
11184 }
11185 }
11186 } elseif (isset($this->objectbuffer[$k]) && $this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
11187 $fontsize = $font[$k]['size'];
11188 $fontdesc = $font[$k]['curr']['desc'];
11189 $lh = 1;
11190 $ypos[$k] = $this->_setLineYpos($fontsize, $fontdesc, $lh, $ypos[-1]); // Lineheight=1 fixed
11191 } elseif (isset($this->objectbuffer[$k])) {
11192 $oh = $this->objectbuffer[$k]['OUTER-HEIGHT'];
11193 $va = $this->objectbuffer[$k]['vertical-align'];
11194
11195 if ($va == 'BS') { // (BASELINE default)
11196 if ($oh > $topy) {
11197 $topy = $oh;
11198 }
11199 } elseif ($va == 'M') {
11200 if (($midpoint + $oh / 2) > $topy) {
11201 $topy = $midpoint + $oh / 2;
11202 }
11203 if (($midpoint - $oh / 2) < $bottomy) {
11204 $bottomy = $midpoint - $oh / 2;
11205 }
11206 } elseif ($va == 'TT') {
11207 if (($ypos[-1]['boxtop'] - $oh) < $bottomy) {
11208 $bottomy = $ypos[-1]['boxtop'] - $oh;
11209 $topy = max($topy, $ypos[-1]['boxtop']);
11210 }
11211 } elseif ($va == 'TB') {
11212 if (($ypos[-1]['boxbottom'] + $oh) > $topy) {
11213 $topy = $ypos[-1]['boxbottom'] + $oh;
11214 $bottomy = min($bottomy, $ypos[-1]['boxbottom']);
11215 }
11216 } elseif ($va == 'T') {
11217 if ($oh > $mta) {
11218 $mta = $oh;
11219 }
11220 } elseif ($va == 'B') {
11221 if ($oh > $mba) {
11222 $mba = $oh;
11223 }
11224 }
11225 } elseif ($content[$k] || $content[$k] === '0') {
11226 // FOR FLOWING BLOCK
11227 $fontsize = $font[$k]['size'];
11228 $fontdesc = $font[$k]['curr']['desc'];
11229 // In future could set CSS line-height from inline elements; for now, use block level:
11230 $ypos[$k] = $this->_setLineYpos($fontsize, $fontdesc, $CSSlineheight, $ypos[-1]);
11231
11232 if (isset($font[$k]['textparam']['text-baseline']) && $font[$k]['textparam']['text-baseline'] != 0) {
11233 $ypos[$k]['baseline-shift'] = $font[$k]['textparam']['text-baseline'];
11234 }
11235
11236 // DO ALIGNMENT FOR BASELINES *******************
11237 // Until most fonts have OpenType BASE tables, this won't work
11238 // $ypos[$k] compared to $ypos[-1] or $ypos[$k-1] using $dominant_baseline and $baseline_table
11239 // UPDATE Maximums
11240 if ($line_stacking_strategy == 'block-line-height' || $line_stacking_strategy == 'grid-height' || $line_stacking_strategy == 'max-height') { // don't include extended block progression of all inline elements
11241 if ($line_stacking_shift == 'disregard-shifts') {
11242 if ($ypos[$k]['boxtop'] > $topy) {
11243 $topy = $ypos[$k]['boxtop'];
11244 }
11245 if ($ypos[$k]['boxbottom'] < $bottomy) {
11246 $bottomy = $ypos[$k]['boxbottom'];
11247 }
11248 } else {
11249 if (($ypos[$k]['boxtop'] + $ypos[$k]['baseline-shift']) > $topy) {
11250 $topy = $ypos[$k]['boxtop'] + $ypos[$k]['baseline-shift'];
11251 }
11252 if (($ypos[$k]['boxbottom'] + $ypos[$k]['baseline-shift']) < $bottomy) {
11253 $bottomy = $ypos[$k]['boxbottom'] + $ypos[$k]['baseline-shift'];
11254 }
11255 }
11256 } else {
11257 if ($line_stacking_shift == 'disregard-shifts') {
11258 if ($ypos[$k]['exttop'] > $topy) {
11259 $topy = $ypos[$k]['exttop'];
11260 }
11261 if ($ypos[$k]['extbottom'] < $bottomy) {
11262 $bottomy = $ypos[$k]['extbottom'];
11263 }
11264 } else {
11265 if (($ypos[$k]['exttop'] + $ypos[$k]['baseline-shift']) > $topy) {
11266 $topy = $ypos[$k]['exttop'] + $ypos[$k]['baseline-shift'];
11267 }
11268 if (($ypos[$k]['extbottom'] + $ypos[$k]['baseline-shift']) < $bottomy) {
11269 $bottomy = $ypos[$k]['extbottom'] + $ypos[$k]['baseline-shift'];
11270 }
11271 }
11272 }
11273
11274 // If BORDER set on inline element
11275 if (isset($font[$k]['bord']) && $font[$k]['bord']) {
11276 $bordfontsize = $font[$k]['textparam']['bord-decoration']['fontsize'] / $shrin_k;
11277 $bordfontkey = $font[$k]['textparam']['bord-decoration']['fontkey'];
11278 if ($bordfontkey != $fontkey || $bordfontsize != $fontsize || isset($font[$k]['textparam']['bord-decoration']['baseline'])) {
11279 $bordfontdesc = $this->fonts[$bordfontkey]['desc'];
11280 $bordypos[$k] = $this->_setLineYpos($bordfontsize, $bordfontdesc, $CSSlineheight, $ypos[-1]);
11281 if (isset($font[$k]['textparam']['bord-decoration']['baseline']) && $font[$k]['textparam']['bord-decoration']['baseline'] != 0) {
11282 $bordypos[$k]['baseline-shift'] = $font[$k]['textparam']['bord-decoration']['baseline'] / $shrin_k;
11283 }
11284 }
11285 }
11286 // If BACKGROUND set on inline element
11287 if (isset($font[$k]['spanbgcolor']) && $font[$k]['spanbgcolor']) {
11288 $bgfontsize = $font[$k]['textparam']['bg-decoration']['fontsize'] / $shrin_k;
11289 $bgfontkey = $font[$k]['textparam']['bg-decoration']['fontkey'];
11290 if ($bgfontkey != $fontkey || $bgfontsize != $fontsize || isset($font[$k]['textparam']['bg-decoration']['baseline'])) {
11291 $bgfontdesc = $this->fonts[$bgfontkey]['desc'];
11292 $bgypos[$k] = $this->_setLineYpos($bgfontsize, $bgfontdesc, $CSSlineheight, $ypos[-1]);
11293 if (isset($font[$k]['textparam']['bg-decoration']['baseline']) && $font[$k]['textparam']['bg-decoration']['baseline'] != 0) {
11294 $bgypos[$k]['baseline-shift'] = $font[$k]['textparam']['bg-decoration']['baseline'] / $shrin_k;
11295 }
11296 }
11297 }
11298 }
11299 }
11300
11301
11302 // TOP or BOTTOM aligned images
11303 if ($mta > ($topy - $bottomy)) {
11304 if (($topy - $mta) < $bottomy) {
11305 $bottomy = $topy - $mta;
11306 }
11307 }
11308 if ($mba > ($topy - $bottomy)) {
11309 if (($bottomy + $mba) > $topy) {
11310 $topy = $bottomy + $mba;
11311 }
11312 }
11313
11314 if ($line_stacking_strategy == 'block-line-height') { // fixed height set by block element (whether present or not)
11315 $topy = $ypos[-1]['exttop'];
11316 $bottomy = $ypos[-1]['extbottom'];
11317 }
11318
11319 $inclusiveHeight = $topy - $bottomy;
11320
11321 // SET $stackHeight taking note of line_stacking_strategy
11322 // NB inclusive height already takes account of need to consider block progression height (excludes leading set by lineheight)
11323 // or extended block progression height (includes leading set by lineheight)
11324 if ($line_stacking_strategy == 'block-line-height') { // fixed = extended block progression height of block element
11325 $stackHeight = $boxLineHeight;
11326 } elseif ($line_stacking_strategy == 'max-height') { // smallest height which includes extended block progression height of block element
11327 // and block progression heights of inline elements (NOT extended)
11328 $stackHeight = $inclusiveHeight;
11329 } elseif ($line_stacking_strategy == 'grid-height') { // smallest multiple of block element lineheight to include
11330 // block progression heights of inline elements (NOT extended)
11331 $stackHeight = $boxLineHeight;
11332 while ($stackHeight < $inclusiveHeight) {
11333 $stackHeight += $boxLineHeight;
11334 }
11335 } else { // 'inline-line-height' = default // smallest height which includes extended block progression height of block element
11336 // AND extended block progression heights of inline elements
11337 $stackHeight = $inclusiveHeight;
11338 }
11339
11340 $diff = $stackHeight - $inclusiveHeight;
11341 $topy += $diff / 2;
11342 $bottomy -= $diff / 2;
11343
11344 // ADJUST $ypos => lineBox using $stackHeight; lineBox are all offsets from the top of stackHeight in mm
11345 // and SET IMAGE OFFSETS
11346 $lineBox[-1]['boxtop'] = $topy - $ypos[-1]['boxtop'];
11347 $lineBox[-1]['boxbottom'] = $topy - $ypos[-1]['boxbottom'];
11348 // $lineBox[-1]['exttop'] = $topy - $ypos[-1]['exttop'];
11349 // $lineBox[-1]['extbottom'] = $topy - $ypos[-1]['extbottom'];
11350 $lineBox[-1]['glyphYorigin'] = $topy - $ypos[-1]['glyphYorigin'];
11351 $lineBox[-1]['baseline-shift'] = $ypos[-1]['baseline-shift'];
11352
11353 $midpoint = $lineBox[-1]['boxbottom'] - (($lineBox[-1]['boxbottom'] - $lineBox[-1]['boxtop']) / 2);
11354
11355 foreach ($content as $k => $chunk) {
11356 if (isset($this->objectbuffer[$k])) {
11357 $oh = $this->objectbuffer[$k]['OUTER-HEIGHT'];
11358 // LIST MARKERS
11359 if ($this->objectbuffer[$k]['type'] == 'listmarker') {
11360 $oh = $fontsize;
11361 } elseif ($this->objectbuffer[$k]['type'] == 'dottab') { // mPDF 6 DOTTAB
11362 $oh = $font[$k]['size']; // == $this->objectbuffer[$k]['fontsize']/Mpdf::SCALE;
11363 $lineBox[$k]['boxtop'] = $topy - $ypos[$k]['boxtop'];
11364 $lineBox[$k]['boxbottom'] = $topy - $ypos[$k]['boxbottom'];
11365 $lineBox[$k]['glyphYorigin'] = $topy - $ypos[$k]['glyphYorigin'];
11366 $lineBox[$k]['baseline-shift'] = 0;
11367 // continue;
11368 }
11369 $va = $this->objectbuffer[$k]['vertical-align']; // = $objattr['vertical-align'] = set as M,T,B,S
11370
11371 if ($va == 'BS') { // (BASELINE default)
11372 $lineBox[$k]['top'] = $lineBox[-1]['glyphYorigin'] - $oh;
11373 } elseif ($va == 'M') {
11374 $lineBox[$k]['top'] = $midpoint - $oh / 2;
11375 } elseif ($va == 'TT') {
11376 $lineBox[$k]['top'] = $lineBox[-1]['boxtop'];
11377 } elseif ($va == 'TB') {
11378 $lineBox[$k]['top'] = $lineBox[-1]['boxbottom'] - $oh;
11379 } elseif ($va == 'T') {
11380 $lineBox[$k]['top'] = 0;
11381 } elseif ($va == 'B') {
11382 $lineBox[$k]['top'] = $stackHeight - $oh;
11383 }
11384 } elseif ($content[$k] || $content[$k] === '0') {
11385 $lineBox[$k]['boxtop'] = $topy - $ypos[$k]['boxtop'];
11386 $lineBox[$k]['boxbottom'] = $topy - $ypos[$k]['boxbottom'];
11387 // $lineBox[$k]['exttop'] = $topy - $ypos[$k]['exttop'];
11388 // $lineBox[$k]['extbottom'] = $topy - $ypos[$k]['extbottom'];
11389 $lineBox[$k]['glyphYorigin'] = $topy - $ypos[$k]['glyphYorigin'];
11390 $lineBox[$k]['baseline-shift'] = $ypos[$k]['baseline-shift'];
11391 if (isset($bordypos[$k]['boxtop'])) {
11392 $lineBox[$k]['border-boxtop'] = $topy - $bordypos[$k]['boxtop'];
11393 $lineBox[$k]['border-boxbottom'] = $topy - $bordypos[$k]['boxbottom'];
11394 $lineBox[$k]['border-baseline-shift'] = $bordypos[$k]['baseline-shift'];
11395 }
11396 if (isset($bgypos[$k]['boxtop'])) {
11397 $lineBox[$k]['background-boxtop'] = $topy - $bgypos[$k]['boxtop'];
11398 $lineBox[$k]['background-boxbottom'] = $topy - $bgypos[$k]['boxbottom'];
11399 $lineBox[$k]['background-baseline-shift'] = $bgypos[$k]['baseline-shift'];
11400 }
11401 }
11402 }
11403 }
11404
11405 function SetBasePath($str = '')
11406 {
11407 if (isset($_SERVER['HTTP_HOST'])) {
11408 $host = $_SERVER['HTTP_HOST'];
11409 } elseif (isset($_SERVER['SERVER_NAME'])) {
11410 $host = $_SERVER['SERVER_NAME'];
11411 } else {
11412 $host = '';
11413 }
11414 if (!$str) {
11415 if (isset($_SERVER['SCRIPT_NAME'])) {
11416 $currentPath = dirname($_SERVER['SCRIPT_NAME']);
11417 } else {
11418 $currentPath = dirname($_SERVER['PHP_SELF']);
11419 }
11420 $currentPath = str_replace("\\", "/", $currentPath);
11421 if ($currentPath == '/') {
11422 $currentPath = '';
11423 }
11424 if ($host) { // mPDF 6
11425 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] && $_SERVER['HTTPS'] !== 'off') {
11426 $currpath = 'https://' . $host . $currentPath . '/';
11427 } else {
11428 $currpath = 'http://' . $host . $currentPath . '/';
11429 }
11430 } else {
11431 $currpath = '';
11432 }
11433 $this->basepath = $currpath;
11434 $this->basepathIsLocal = true;
11435 return;
11436 }
11437 $str = preg_replace('/\?.*/', '', $str);
11438 if (!preg_match('/(http|https|ftp):\/\/.*\//i', $str)) {
11439 $str .= '/';
11440 }
11441 $str .= 'xxx'; // in case $str ends in / e.g. http://www.bbc.co.uk/
11442 $this->basepath = dirname($str) . "/"; // returns e.g. e.g. http://www.google.com/dir1/dir2/dir3/
11443 $this->basepath = str_replace("\\", "/", $this->basepath); // If on Windows
11444 $tr = parse_url($this->basepath);
11445 if (isset($tr['host']) && ($tr['host'] == $host)) {
11446 $this->basepathIsLocal = true;
11447 } else {
11448 $this->basepathIsLocal = false;
11449 }
11450 }
11451
11452 public function GetFullPath(&$path, $basepath = '')
11453 {
11454 // When parsing CSS need to pass temporary basepath - so links are relative to current stylesheet
11455 if (!$basepath) {
11456 $basepath = $this->basepath;
11457 }
11458
11459 // Fix path value
11460 $path = str_replace("\\", '/', $path); // If on Windows
11461
11462 // mPDF 5.7.2
11463 if (substr($path, 0, 2) === '//') {
11464 $scheme = parse_url($basepath, PHP_URL_SCHEME);
11465 $scheme = $scheme ?: 'http';
11466 $path = $scheme . ':' . $path;
11467 }
11468
11469 $path = preg_replace('|^./|', '', $path); // Inadvertently corrects "./path/etc" and "//www.domain.com/etc"
11470
11471 if (substr($path, 0, 1) == '#') {
11472 return;
11473 }
11474
11475 // Skip schemes not supported by installed stream wrappers
11476 $wrappers = stream_get_wrappers();
11477 $pattern = sprintf('@^(?!%s)[a-z0-9\.\-+]+:.*@i', implode('|', $wrappers));
11478 if (preg_match($pattern, $path)) {
11479 return;
11480 }
11481
11482 if (substr($path, 0, 3) == "../") { // It is a relative link
11483
11484 $backtrackamount = substr_count($path, "../");
11485 $maxbacktrack = substr_count($basepath, "/") - 3;
11486 $filepath = str_replace("../", '', $path);
11487 $path = $basepath;
11488
11489 // If it is an invalid relative link, then make it go to directory root
11490 if ($backtrackamount > $maxbacktrack) {
11491 $backtrackamount = $maxbacktrack;
11492 }
11493
11494 // Backtrack some directories
11495 for ($i = 0; $i < $backtrackamount + 1; $i++) {
11496 $path = substr($path, 0, strrpos($path, "/"));
11497 }
11498
11499 $path = $path . "/" . $filepath; // Make it an absolute path
11500
11501 } elseif ((strpos($path, ":/") === false || strpos($path, ":/") > 10) && !@is_file($path)) { // It is a local link. Ignore potential file errors
11502
11503 if (substr($path, 0, 1) == "/") {
11504
11505 $tr = parse_url($basepath);
11506
11507 // mPDF 5.7.2
11508 $root = '';
11509 if (!empty($tr['scheme'])) {
11510 $root .= $tr['scheme'] . '://';
11511 }
11512
11513 $root .= isset($tr['host']) ? $tr['host'] : '';
11514 $root .= ((isset($tr['port']) && $tr['port']) ? (':' . $tr['port']) : ''); // mPDF 5.7.3
11515
11516 $path = $root . $path;
11517
11518 } else {
11519 $path = $basepath . $path;
11520 }
11521 }
11522 // Do nothing if it is an Absolute Link
11523 }
11524
11525 function docPageNum($num = 0, $extras = false)
11526 {
11527 if ($num < 1) {
11528 $num = $this->page;
11529 }
11530
11531 $type = $this->defaultPageNumStyle; // set default Page Number Style
11532 $ppgno = $num;
11533 $suppress = 0;
11534 $offset = 0;
11535 $lastreset = 0;
11536
11537 foreach ($this->PageNumSubstitutions as $psarr) {
11538
11539 if ($num >= $psarr['from']) {
11540
11541 if ($psarr['reset']) {
11542 if ($psarr['reset'] > 1) {
11543 $offset = $psarr['reset'] - 1;
11544 }
11545 $ppgno = $num - $psarr['from'] + 1 + $offset;
11546 $lastreset = $psarr['from'];
11547 }
11548
11549 if ($psarr['type']) {
11550 $type = $psarr['type'];
11551 }
11552
11553 if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
11554 $suppress = 1;
11555 } elseif (strtoupper($psarr['suppress']) == 'OFF') {
11556 $suppress = 0;
11557 }
11558 }
11559 }
11560
11561 if ($suppress) {
11562 return '';
11563 }
11564
11565 $ppgno = $this->_getStyledNumber($ppgno, $type);
11566
11567 if ($extras) {
11568 $ppgno = $this->pagenumPrefix . $ppgno . $this->pagenumSuffix;
11569 }
11570
11571 return $ppgno;
11572 }
11573
11574 function docPageNumTotal($num = 0, $extras = false)
11575 {
11576 if ($num < 1) {
11577 $num = $this->page;
11578 }
11579
11580 $type = $this->defaultPageNumStyle; // set default Page Number Style
11581 $ppgstart = 1;
11582 $ppgend = count($this->pages) + 1;
11583 $suppress = 0;
11584 $offset = 0;
11585
11586 foreach ($this->PageNumSubstitutions as $psarr) {
11587 if ($num >= $psarr['from']) {
11588 if ($psarr['reset']) {
11589 if ($psarr['reset'] > 1) {
11590 $offset = $psarr['reset'] - 1;
11591 }
11592 $ppgstart = $psarr['from'] + $offset;
11593 $ppgend = count($this->pages) + 1 + $offset;
11594 }
11595 if ($psarr['type']) {
11596 $type = $psarr['type'];
11597 }
11598 if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
11599 $suppress = 1;
11600 } elseif (strtoupper($psarr['suppress']) == 'OFF') {
11601 $suppress = 0;
11602 }
11603 }
11604 if ($num < $psarr['from']) {
11605 if ($psarr['reset']) {
11606 $ppgend = $psarr['from'] + $offset;
11607 break;
11608 }
11609 }
11610 }
11611
11612 if ($suppress) {
11613 return '';
11614 }
11615
11616 $ppgno = $ppgend - $ppgstart + $offset;
11617 $ppgno = $this->_getStyledNumber($ppgno, $type);
11618
11619 if ($extras) {
11620 $ppgno = $this->pagenumPrefix . $ppgno . $this->pagenumSuffix;
11621 }
11622
11623 return $ppgno;
11624 }
11625
11626 // mPDF 6
11627 function _getStyledNumber($ppgno, $type, $listmarker = false)
11628 {
11629 if ($listmarker) {
11630 $reverse = true; // Reverse RTL numerals (Hebrew) when using for list
11631 $checkfont = true; // Using list - font is set, so check if character is available
11632 } else {
11633 $reverse = false; // For pagenumbers, RTL numerals (Hebrew) will get reversed later by bidi
11634 $checkfont = false; // For pagenumbers - font is not set, so no check
11635 }
11636
11637 $decToAlpha = new Conversion\DecToAlpha();
11638 $decToCjk = new Conversion\DecToCjk();
11639 $decToHebrew = new Conversion\DecToHebrew();
11640 $decToRoman = new Conversion\DecToRoman();
11641 $decToOther = new Conversion\DecToOther($this);
11642
11643 $lowertype = strtolower($type);
11644
11645 if ($lowertype == 'upper-latin' || $lowertype == 'upper-alpha' || $type == 'A') {
11646
11647 $ppgno = $decToAlpha->convert($ppgno, true);
11648
11649 } elseif ($lowertype == 'lower-latin' || $lowertype == 'lower-alpha' || $type == 'a') {
11650
11651 $ppgno = $decToAlpha->convert($ppgno, false);
11652
11653 } elseif ($lowertype == 'upper-roman' || $type == 'I') {
11654
11655 $ppgno = $decToRoman->convert($ppgno, true);
11656
11657 } elseif ($lowertype == 'lower-roman' || $type == 'i') {
11658
11659 $ppgno = $decToRoman->convert($ppgno, false);
11660
11661 } elseif ($lowertype == 'hebrew') {
11662
11663 $ppgno = $decToHebrew->convert($ppgno, $reverse);
11664
11665 } elseif (preg_match('/(arabic-indic|bengali|devanagari|gujarati|gurmukhi|kannada|malayalam|oriya|persian|tamil|telugu|thai|urdu|cambodian|khmer|lao|myanmar)/i', $lowertype, $m)) {
11666
11667 $cp = $decToOther->getCodePage($m[1]);
11668 $ppgno = $decToOther->convert($ppgno, $cp, $checkfont);
11669
11670 } elseif ($lowertype == 'cjk-decimal') {
11671
11672 $ppgno = $decToCjk->convert($ppgno);
11673
11674 }
11675
11676 return $ppgno;
11677 }
11678
11679 function docPageSettings($num = 0)
11680 {
11681 // Returns current type (numberstyle), suppression state for this page number;
11682 // reset is only returned if set for this page number
11683 if ($num < 1) {
11684 $num = $this->page;
11685 }
11686
11687 $type = $this->defaultPageNumStyle; // set default Page Number Style
11688 $ppgno = $num;
11689 $suppress = 0;
11690 $offset = 0;
11691 $reset = '';
11692
11693 foreach ($this->PageNumSubstitutions as $psarr) {
11694 if ($num >= $psarr['from']) {
11695 if ($psarr['reset']) {
11696 if ($psarr['reset'] > 1) {
11697 $offset = $psarr['reset'] - 1;
11698 }
11699 $ppgno = $num - $psarr['from'] + 1 + $offset;
11700 }
11701 if ($psarr['type']) {
11702 $type = $psarr['type'];
11703 }
11704 if (strtoupper($psarr['suppress']) == 'ON' || $psarr['suppress'] == 1) {
11705 $suppress = 1;
11706 } elseif (strtoupper($psarr['suppress']) == 'OFF') {
11707 $suppress = 0;
11708 }
11709 }
11710 if ($num == $psarr['from']) {
11711 $reset = $psarr['reset'];
11712 }
11713 }
11714
11715 if ($suppress) {
11716 $suppress = 'on';
11717 } else {
11718 $suppress = 'off';
11719 }
11720
11721 return [$type, $suppress, $reset];
11722 }
11723
11725 {
11726 $this->docTemplateStart = $this->page;
11727 }
11728
11729 // Page header
11730 function Header($content = '')
11731 {
11732
11733 $this->cMarginL = 0;
11734 $this->cMarginR = 0;
11735
11736
11737 if (($this->mirrorMargins && ($this->page % 2 == 0) && $this->HTMLHeaderE) || ($this->mirrorMargins && ($this->page % 2 == 1) && $this->HTMLHeader) || (!$this->mirrorMargins && $this->HTMLHeader)) {
11738 $this->writeHTMLHeaders();
11739 return;
11740 }
11741 }
11742
11743 /* -- TABLES -- */
11744 function TableHeaderFooter($content = '', $tablestartpage = '', $tablestartcolumn = '', $horf = 'H', $level = 0, $firstSpread = true, $finalSpread = true)
11745 {
11746 if (($horf == 'H' || $horf == 'F') && !empty($content)) { // mPDF 5.7.2
11747 $table = &$this->table[1][1];
11748
11749 // mPDF 5.7.2
11750 if ($horf == 'F') { // Table Footer
11751 $firstrow = count($table['cells']) - $table['footernrows'];
11752 $lastrow = count($table['cells']) - 1;
11753 } else { // Table Header
11754 $firstrow = 0;
11755 $lastrow = $table['headernrows'] - 1;
11756 }
11757 if (empty($content[$firstrow])) {
11758 if ($this->debug) {
11759 throw new \Mpdf\MpdfException("<tfoot> must precede <tbody> in a table");
11760 } else {
11761 return;
11762 }
11763 }
11764
11765
11766 // Advance down page by half width of top border
11767 if ($horf == 'H') { // Only if header
11768 if ($table['borders_separate']) {
11769 $adv = $table['border_spacing_V'] / 2 + $table['border_details']['T']['w'] + $table['padding']['T'];
11770 } else {
11771 $adv = $table['max_cell_border_width']['T'] / 2;
11772 }
11773 if ($adv) {
11774 if ($this->table_rotate) {
11775 $this->y += ($adv);
11776 } else {
11777 $this->DivLn($adv, $this->blklvl, true);
11778 }
11779 }
11780 }
11781
11782 $topy = $content[$firstrow][0]['y'] - $this->y;
11783
11784 for ($i = $firstrow; $i <= $lastrow; $i++) {
11785 $y = $this->y;
11786
11787 /* -- COLUMNS -- */
11788 // If outside columns, this is done in PaintDivBB
11789 if ($this->ColActive) {
11790 // OUTER FILL BGCOLOR of DIVS
11791 if ($this->blklvl > 0) {
11792 $firstblockfill = $this->GetFirstBlockFill();
11793 if ($firstblockfill && $this->blklvl >= $firstblockfill) {
11794 $divh = $content[$i][0]['h'];
11795 $bak_x = $this->x;
11796 $this->DivLn($divh, -3, false);
11797 // Reset current block fill
11798 $bcor = $this->blk[$this->blklvl]['bgcolorarray'];
11799 $this->SetFColor($bcor);
11800 $this->x = $bak_x;
11801 }
11802 }
11803 }
11804 /* -- END COLUMNS -- */
11805
11806 $colctr = 0;
11807 foreach ($content[$i] as $tablehf) {
11808 $colctr++;
11809 $y = Arrays::get($tablehf, 'y', null) - $topy;
11810 $this->y = $y;
11811 // Set some cell values
11812 $x = Arrays::get($tablehf, 'x', null);
11813 if (($this->mirrorMargins) && ($tablestartpage == 'ODD') && (($this->page) % 2 == 0)) { // EVEN
11814 $x = $x + $this->MarginCorrection;
11815 } elseif (($this->mirrorMargins) && ($tablestartpage == 'EVEN') && (($this->page) % 2 == 1)) { // ODD
11816 $x = $x + $this->MarginCorrection;
11817 }
11818 /* -- COLUMNS -- */
11819 // Added to correct for Columns
11820 if ($this->ColActive) {
11821 if ($this->directionality == 'rtl') { // *OTL*
11822 $x -= ($this->CurrCol - $tablestartcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
11823 } // *OTL*
11824 else { // *OTL*
11825 $x += ($this->CurrCol - $tablestartcolumn) * ($this->ColWidth + $this->ColGap);
11826 } // *OTL*
11827 }
11828 /* -- END COLUMNS -- */
11829
11830 if ($colctr == 1) {
11831 $x0 = $x;
11832 }
11833
11834 // mPDF ITERATION
11835 if ($this->iterationCounter) {
11836 foreach ($tablehf['textbuffer'] as $k => $t) {
11837 if (!is_array($t[0]) && preg_match('/{iteration ([a-zA-Z0-9_]+)}/', $t[0], $m)) {
11838 $vname = '__' . $m[1] . '_';
11839 if (!isset($this->$vname)) {
11840 $this->$vname = 1;
11841 } else {
11842 $this->$vname++;
11843 }
11844 $tablehf['textbuffer'][$k][0] = preg_replace('/{iteration ' . $m[1] . '}/', $this->$vname, $tablehf['textbuffer'][$k][0]);
11845 }
11846 }
11847 }
11848
11849 $w = Arrays::get($tablehf, 'w', null);
11850 $h = Arrays::get($tablehf, 'h', null);
11851 $va = Arrays::get($tablehf, 'va', null);
11852 $R = Arrays::get($tablehf, 'R', null);
11853 $direction = Arrays::get($tablehf, 'direction', null);
11854 $mih = Arrays::get($tablehf, 'mih', null);
11855 $border = Arrays::get($tablehf, 'border', null);
11856 $border_details = Arrays::get($tablehf, 'border_details', null);
11857 $padding = Arrays::get($tablehf, 'padding', null);
11858 $this->tabletheadjustfinished = true;
11859
11860 $textbuffer = Arrays::get($tablehf, 'textbuffer', null);
11861
11862 // Align
11863 $align = Arrays::get($tablehf, 'a', null);
11864 $this->cellTextAlign = $align;
11865
11866 $this->cellLineHeight = Arrays::get($tablehf, 'cellLineHeight', null);
11867 $this->cellLineStackingStrategy = Arrays::get($tablehf, 'cellLineStackingStrategy', null);
11868 $this->cellLineStackingShift = Arrays::get($tablehf, 'cellLineStackingShift', null);
11869
11870 $this->x = $x;
11871
11872 if ($this->ColActive) {
11873 if ($table['borders_separate']) {
11874 $tablefill = isset($table['bgcolor'][-1]) ? $table['bgcolor'][-1] : 0;
11875 if ($tablefill) {
11876 $color = $this->colorConverter->convert($tablefill, $this->PDFAXwarnings);
11877 if ($color) {
11878 $xadj = ($table['border_spacing_H'] / 2);
11879 $yadj = ($table['border_spacing_V'] / 2);
11880 $wadj = $table['border_spacing_H'];
11881 $hadj = $table['border_spacing_V'];
11882 if ($i == $firstrow && $horf == 'H') { // Top
11883 $yadj += $table['padding']['T'] + $table['border_details']['T']['w'];
11884 $hadj += $table['padding']['T'] + $table['border_details']['T']['w'];
11885 }
11886 if (($i == ($lastrow) || (isset($tablehf['rowspan']) && ($i + $tablehf['rowspan']) == ($lastrow + 1)) || (!isset($tablehf['rowspan']) && ($i + 1) == ($lastrow + 1))) && $horf == 'F') { // Bottom
11887 $hadj += $table['padding']['B'] + $table['border_details']['B']['w'];
11888 }
11889 if ($colctr == 1) { // Left
11890 $xadj += $table['padding']['L'] + $table['border_details']['L']['w'];
11891 $wadj += $table['padding']['L'] + $table['border_details']['L']['w'];
11892 }
11893 if ($colctr == count($content[$i])) { // Right
11894 $wadj += $table['padding']['R'] + $table['border_details']['R']['w'];
11895 }
11896 $this->SetFColor($color);
11897 $this->Rect($x - $xadj, $y - $yadj, $w + $wadj, $h + $hadj, 'F');
11898 }
11899 }
11900 }
11901 }
11902
11903 if ($table['empty_cells'] != 'hide' || !empty($textbuffer) || !$table['borders_separate']) {
11904 $paintcell = true;
11905 } else {
11906 $paintcell = false;
11907 }
11908
11909 // Vertical align
11910 if ($R && intval($R) > 0 && isset($va) && $va != 'B') {
11911 $va = 'B';
11912 }
11913
11914 if (!isset($va) || empty($va) || $va == 'M') {
11915 $this->y += ($h - $mih) / 2;
11916 } elseif (isset($va) && $va == 'B') {
11917 $this->y += $h - $mih;
11918 }
11919
11920
11921 // TABLE ROW OR CELL FILL BGCOLOR
11922 $fill = 0;
11923 if (isset($tablehf['bgcolor']) && $tablehf['bgcolor'] && $tablehf['bgcolor'] != 'transparent') {
11924 $fill = $tablehf['bgcolor'];
11925 $leveladj = 6;
11926 } elseif (isset($content[$i][0]['trbgcolor']) && $content[$i][0]['trbgcolor'] && $content[$i][0]['trbgcolor'] != 'transparent') { // Row color
11927 $fill = $content[$i][0]['trbgcolor'];
11928 $leveladj = 3;
11929 }
11930 if ($fill && $paintcell) {
11931 $color = $this->colorConverter->convert($fill, $this->PDFAXwarnings);
11932 if ($color) {
11933 if ($table['borders_separate']) {
11934 if ($this->ColActive) {
11935 $this->SetFColor($color);
11936 $this->Rect($x + ($table['border_spacing_H'] / 2), $y + ($table['border_spacing_V'] / 2), $w - $table['border_spacing_H'], $h - $table['border_spacing_V'], 'F');
11937 } else {
11938 $this->tableBackgrounds[$level * 9 + $leveladj][] = ['gradient' => false, 'x' => ($x + ($table['border_spacing_H'] / 2)), 'y' => ($y + ($table['border_spacing_V'] / 2)), 'w' => ($w - $table['border_spacing_H']), 'h' => ($h - $table['border_spacing_V']), 'col' => $color];
11939 }
11940 } else {
11941 if ($this->ColActive) {
11942 $this->SetFColor($color);
11943 $this->Rect($x, $y, $w, $h, 'F');
11944 } else {
11945 $this->tableBackgrounds[$level * 9 + $leveladj][] = ['gradient' => false, 'x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'col' => $color];
11946 }
11947 }
11948 }
11949 }
11950
11951
11952 /* -- BACKGROUNDS -- */
11953 if (isset($tablehf['gradient']) && $tablehf['gradient'] && $paintcell) {
11954 $g = $this->gradient->parseBackgroundGradient($tablehf['gradient']);
11955 if ($g) {
11956 if ($table['borders_separate']) {
11957 $px = $x + ($table['border_spacing_H'] / 2);
11958 $py = $y + ($table['border_spacing_V'] / 2);
11959 $pw = $w - $table['border_spacing_H'];
11960 $ph = $h - $table['border_spacing_V'];
11961 } else {
11962 $px = $x;
11963 $py = $y;
11964 $pw = $w;
11965 $ph = $h;
11966 }
11967 if ($this->ColActive) {
11968 $this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
11969 } else {
11970 $this->tableBackgrounds[$level * 9 + 7][] = ['gradient' => true, 'x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
11971 }
11972 }
11973 }
11974
11975 if (isset($tablehf['background-image']) && $paintcell) {
11976 if ($tablehf['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $tablehf['background-image']['gradient'])) {
11977 $g = $this->gradient->parseMozGradient($tablehf['background-image']['gradient']);
11978 if ($g) {
11979 if ($table['borders_separate']) {
11980 $px = $x + ($table['border_spacing_H'] / 2);
11981 $py = $y + ($table['border_spacing_V'] / 2);
11982 $pw = $w - $table['border_spacing_H'];
11983 $ph = $h - $table['border_spacing_V'];
11984 } else {
11985 $px = $x;
11986 $py = $y;
11987 $pw = $w;
11988 $ph = $h;
11989 }
11990 if ($this->ColActive) {
11991 $this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
11992 } else {
11993 $this->tableBackgrounds[$level * 9 + 7][] = ['gradient' => true, 'x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
11994 }
11995 }
11996 } elseif ($tablehf['background-image']['image_id']) { // Background pattern
11997 $n = count($this->patterns) + 1;
11998 if ($table['borders_separate']) {
11999 $px = $x + ($table['border_spacing_H'] / 2);
12000 $py = $y + ($table['border_spacing_V'] / 2);
12001 $pw = $w - $table['border_spacing_H'];
12002 $ph = $h - $table['border_spacing_V'];
12003 } else {
12004 $px = $x;
12005 $py = $y;
12006 $pw = $w;
12007 $ph = $h;
12008 }
12009 if ($this->ColActive) {
12010 list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($tablehf['background-image']['orig_w'], $tablehf['background-image']['orig_h'], $pw, $ph, $tablehf['background-image']['resize'], $tablehf['background-image']['x_repeat'], $tablehf['background-image']['y_repeat']);
12011 $this->patterns[$n] = ['x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'pgh' => $this->h, 'image_id' => $tablehf['background-image']['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $tablehf['background-image']['x_pos'], 'y_pos' => $tablehf['background-image']['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'itype' => $tablehf['background-image']['itype']];
12012 if ($tablehf['background-image']['opacity'] > 0 && $tablehf['background-image']['opacity'] < 1) {
12013 $opac = $this->SetAlpha($tablehf['background-image']['opacity'], 'Normal', true);
12014 } else {
12015 $opac = '';
12016 }
12017 $this->writer->write(sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $px * Mpdf::SCALE, ($this->h - $py) * Mpdf::SCALE, $pw * Mpdf::SCALE, -$ph * Mpdf::SCALE));
12018 } else {
12019 $this->tableBackgrounds[$level * 9 + 8][] = ['x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'image_id' => $tablehf['background-image']['image_id'], 'orig_w' => $tablehf['background-image']['orig_w'], 'orig_h' => $tablehf['background-image']['orig_h'], 'x_pos' => $tablehf['background-image']['x_pos'], 'y_pos' => $tablehf['background-image']['y_pos'], 'x_repeat' => $tablehf['background-image']['x_repeat'], 'y_repeat' => $tablehf['background-image']['y_repeat'], 'clippath' => '', 'resize' => $tablehf['background-image']['resize'], 'opacity' => $tablehf['background-image']['opacity'], 'itype' => $tablehf['background-image']['itype']];
12020 }
12021 }
12022 }
12023 /* -- END BACKGROUNDS -- */
12024
12025 // Cell Border
12026 if ($table['borders_separate'] && $paintcell && $border) {
12027 $this->_tableRect($x + ($table['border_spacing_H'] / 2) + ($border_details['L']['w'] / 2), $y + ($table['border_spacing_V'] / 2) + ($border_details['T']['w'] / 2), $w - $table['border_spacing_H'] - ($border_details['L']['w'] / 2) - ($border_details['R']['w'] / 2), $h - $table['border_spacing_V'] - ($border_details['T']['w'] / 2) - ($border_details['B']['w'] / 2), $border, $border_details, false, $table['borders_separate']);
12028 } elseif ($paintcell && $border) {
12029 $this->_tableRect($x, $y, $w, $h, $border, $border_details, true, $table['borders_separate']); // true causes buffer
12030 }
12031
12032 // Print cell content
12033 if (!empty($textbuffer)) {
12034 if ($horf == 'F' && preg_match('/{colsum([0-9]*)[_]*}/', $textbuffer[0][0], $m)) {
12035 $rep = sprintf("%01." . intval($m[1]) . "f", $this->colsums[$colctr - 1]);
12036 $textbuffer[0][0] = preg_replace('/{colsum[0-9_]*}/', $rep, $textbuffer[0][0]);
12037 }
12038
12039 if ($R) {
12040 $cellPtSize = $textbuffer[0][11] / $this->shrin_k;
12041 if (!$cellPtSize) {
12042 $cellPtSize = $this->default_font_size;
12043 }
12044 $cellFontHeight = ($cellPtSize / Mpdf::SCALE);
12045 $opx = $this->x;
12046 $opy = $this->y;
12047 $angle = intval($R);
12048
12049 // Only allow 45 - 90 degrees (when bottom-aligned) or -90
12050 if ($angle > 90) {
12051 $angle = 90;
12052 } elseif ($angle > 0 && (isset($va) && $va != 'B')) {
12053 $angle = 90;
12054 } elseif ($angle > 0 && $angle < 45) {
12055 $angle = 45;
12056 } elseif ($angle < 0) {
12057 $angle = -90;
12058 }
12059
12060 $offset = ((sin(deg2rad($angle))) * 0.37 * $cellFontHeight);
12061 if (isset($align) && $align == 'R') {
12062 $this->x += ($w) + ($offset) - ($cellFontHeight / 3) - ($padding['R'] + $border_details['R']['w']);
12063 } elseif (!isset($align) || $align == 'C') {
12064 $this->x += ($w / 2) + ($offset);
12065 } else {
12066 $this->x += ($offset) + ($cellFontHeight / 3) + ($padding['L'] + $border_details['L']['w']);
12067 }
12068 $str = '';
12069 foreach ($tablehf['textbuffer'] as $t) {
12070 $str .= $t[0] . ' ';
12071 }
12072 $str = rtrim($str);
12073
12074 if (!isset($va) || $va == 'M') {
12075 $this->y -= ($h - $mih) / 2; // Undo what was added earlier VERTICAL ALIGN
12076 if ($angle > 0) {
12077 $this->y += (($h - $mih) / 2) + ($padding['T'] + $border_details['T']['w']) + ($mih - ($padding['T'] + $border_details['T']['w'] + $border_details['B']['w'] + $padding['B']));
12078 } elseif ($angle < 0) {
12079 $this->y += (($h - $mih) / 2) + ($padding['T'] + $border_details['T']['w']);
12080 }
12081 } elseif (isset($va) && $va == 'B') {
12082 $this->y -= $h - $mih; // Undo what was added earlier VERTICAL ALIGN
12083 if ($angle > 0) {
12084 $this->y += $h - ($border_details['B']['w'] + $padding['B']);
12085 } elseif ($angle < 0) {
12086 $this->y += $h - $mih + ($padding['T'] + $border_details['T']['w']);
12087 }
12088 } elseif (isset($va) && $va == 'T') {
12089 if ($angle > 0) {
12090 $this->y += $mih - ($border_details['B']['w'] + $padding['B']);
12091 } elseif ($angle < 0) {
12092 $this->y += ($padding['T'] + $border_details['T']['w']);
12093 }
12094 }
12095
12096 $this->Rotate($angle, $this->x, $this->y);
12097 $s_fs = $this->FontSizePt;
12098 $s_f = $this->FontFamily;
12099 $s_st = $this->FontStyle;
12100 if (!empty($textbuffer[0][3])) { // Font Color
12101 $cor = $textbuffer[0][3];
12102 $this->SetTColor($cor);
12103 }
12104 $this->SetFont($textbuffer[0][4], $textbuffer[0][2], $cellPtSize, true, true);
12105
12106 $this->magic_reverse_dir($str, $this->directionality, $textbuffer[0][18]);
12107 $this->Text($this->x, $this->y, $str, $textbuffer[0][18], $textbuffer[0][8]); // textvar
12108 $this->Rotate(0);
12109 $this->SetFont($s_f, $s_st, $s_fs, true, true);
12110 $this->SetTColor(0);
12111 $this->x = $opx;
12112 $this->y = $opy;
12113 } else {
12114 if ($table['borders_separate']) { // NB twice border width
12115 $xadj = $border_details['L']['w'] + $padding['L'] + ($table['border_spacing_H'] / 2);
12116 $wadj = $border_details['L']['w'] + $border_details['R']['w'] + $padding['L'] + $padding['R'] + $table['border_spacing_H'];
12117 $yadj = $border_details['T']['w'] + $padding['T'] + ($table['border_spacing_H'] / 2);
12118 } else {
12119 $xadj = $border_details['L']['w'] / 2 + $padding['L'];
12120 $wadj = ($border_details['L']['w'] + $border_details['R']['w']) / 2 + $padding['L'] + $padding['R'];
12121 $yadj = $border_details['T']['w'] / 2 + $padding['T'];
12122 }
12123
12124 $this->divwidth = $w - ($wadj);
12125 $this->x += $xadj;
12126 $this->y += $yadj;
12127 $this->printbuffer($textbuffer, '', true, false, $direction);
12128 }
12129 }
12130 $textbuffer = [];
12131
12132 /* -- BACKGROUNDS -- */
12133 if (!$this->ColActive) {
12134 if (isset($content[$i][0]['trgradients']) && ($colctr == 1 || $table['borders_separate'])) {
12135 $g = $this->gradient->parseBackgroundGradient($content[$i][0]['trgradients']);
12136 if ($g) {
12137 $gx = $x0;
12138 $gy = $y;
12139 $gh = $h;
12140 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
12141 if ($table['borders_separate']) {
12142 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
12143 $clx = $x + ($table['border_spacing_H'] / 2);
12144 $cly = $y + ($table['border_spacing_V'] / 2);
12145 $clw = $w - $table['border_spacing_H'];
12146 $clh = $h - $table['border_spacing_V'];
12147 // Set clipping path
12148 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
12149 $this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => $s];
12150 } else {
12151 $this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
12152 }
12153 }
12154 }
12155
12156 if (isset($content[$i][0]['trbackground-images']) && ($colctr == 1 || $table['borders_separate'])) {
12157 if ($content[$i][0]['trbackground-images']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $content[$i][0]['trbackground-images']['gradient'])) {
12158 $g = $this->gradient->parseMozGradient($content[$i][0]['trbackground-images']['gradient']);
12159 if ($g) {
12160 $gx = $x0;
12161 $gy = $y;
12162 $gh = $h;
12163 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
12164 if ($table['borders_separate']) {
12165 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
12166 $clx = $x + ($table['border_spacing_H'] / 2);
12167 $cly = $y + ($table['border_spacing_V'] / 2);
12168 $clw = $w - $table['border_spacing_H'];
12169 $clh = $h - $table['border_spacing_V'];
12170 // Set clipping path
12171 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
12172 $this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => $s];
12173 } else {
12174 $this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
12175 }
12176 }
12177 } else {
12178 $image_id = $content[$i][0]['trbackground-images']['image_id'];
12179 $orig_w = $content[$i][0]['trbackground-images']['orig_w'];
12180 $orig_h = $content[$i][0]['trbackground-images']['orig_h'];
12181 $x_pos = $content[$i][0]['trbackground-images']['x_pos'];
12182 $y_pos = $content[$i][0]['trbackground-images']['y_pos'];
12183 $x_repeat = $content[$i][0]['trbackground-images']['x_repeat'];
12184 $y_repeat = $content[$i][0]['trbackground-images']['y_repeat'];
12185 $resize = $content[$i][0]['trbackground-images']['resize'];
12186 $opacity = $content[$i][0]['trbackground-images']['opacity'];
12187 $itype = $content[$i][0]['trbackground-images']['itype'];
12188
12189 $clippath = '';
12190 $gx = $x0;
12191 $gy = $y;
12192 $gh = $h;
12193 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
12194 if ($table['borders_separate']) {
12195 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
12196 $clx = $x + ($table['border_spacing_H'] / 2);
12197 $cly = $y + ($table['border_spacing_V'] / 2);
12198 $clw = $w - $table['border_spacing_H'];
12199 $clh = $h - $table['border_spacing_V'];
12200 // Set clipping path
12201 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
12202 $this->tableBackgrounds[$level * 9 + 5][] = ['x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => $s, 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
12203 } else {
12204 $this->tableBackgrounds[$level * 9 + 5][] = ['x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => '', 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
12205 }
12206 }
12207 }
12208 }
12209 /* -- END BACKGROUNDS -- */
12210
12211 // TABLE BORDER - if separate OR collapsed and only table border
12212 if (($table['borders_separate'] || ($this->simpleTables && !$table['simple']['border'])) && $table['border']) {
12213 $halfspaceL = $table['padding']['L'] + ($table['border_spacing_H'] / 2);
12214 $halfspaceR = $table['padding']['R'] + ($table['border_spacing_H'] / 2);
12215 $halfspaceT = $table['padding']['T'] + ($table['border_spacing_V'] / 2);
12216 $halfspaceB = $table['padding']['B'] + ($table['border_spacing_V'] / 2);
12217 $tbx = $x;
12218 $tby = $y;
12219 $tbw = $w;
12220 $tbh = $h;
12221 $tab_bord = 0;
12222 $corner = '';
12223 if ($i == $firstrow && $horf == 'H') { // Top
12224 $tby -= $halfspaceT + ($table['border_details']['T']['w'] / 2);
12225 $tbh += $halfspaceT + ($table['border_details']['T']['w'] / 2);
12226 $this->setBorder($tab_bord, Border::TOP);
12227 $corner .= 'T';
12228 }
12229 if (($i == ($lastrow) || (isset($tablehf['rowspan']) && ($i + $tablehf['rowspan']) == ($lastrow + 1))) && $horf == 'F') { // Bottom
12230 $tbh += $halfspaceB + ($table['border_details']['B']['w'] / 2);
12231 $this->setBorder($tab_bord, Border::BOTTOM);
12232 $corner .= 'B';
12233 }
12234 if ($colctr == 1 && $firstSpread) { // Left
12235 $tbx -= $halfspaceL + ($table['border_details']['L']['w'] / 2);
12236 $tbw += $halfspaceL + ($table['border_details']['L']['w'] / 2);
12237 $this->setBorder($tab_bord, Border::LEFT);
12238 $corner .= 'L';
12239 }
12240 if ($colctr == count($content[$i]) && $finalSpread) { // Right
12241 $tbw += $halfspaceR + ($table['border_details']['R']['w'] / 2);
12242 $this->setBorder($tab_bord, Border::RIGHT);
12243 $corner .= 'R';
12244 }
12245 $this->_tableRect($tbx, $tby, $tbw, $tbh, $tab_bord, $table['border_details'], false, $table['borders_separate'], 'table', $corner, $table['border_spacing_V'], $table['border_spacing_H']);
12246 }
12247 }// end column $content
12248 $this->y = $y + $h; // Update y coordinate
12249 }// end row $i
12250 unset($table);
12251 $this->colsums = [];
12252 }
12253 }
12254
12255 /* -- END TABLES -- */
12256
12257 function SetHTMLHeader($header = '', $OE = '', $write = false)
12258 {
12259
12260 $height = 0;
12261 if (is_array($header) && isset($header['html']) && $header['html']) {
12262 $Hhtml = $header['html'];
12263 if ($this->setAutoTopMargin) {
12264 if (isset($header['h'])) {
12265 $height = $header['h'];
12266 } else {
12267 $height = $this->_getHtmlHeight($Hhtml);
12268 }
12269 }
12270 } elseif (!is_array($header) && $header) {
12271 $Hhtml = $header;
12272 if ($this->setAutoTopMargin) {
12273 $height = $this->_getHtmlHeight($Hhtml);
12274 }
12275 } else {
12276 $Hhtml = '';
12277 }
12278
12279 if ($OE !== 'E') {
12280 $OE = 'O';
12281 }
12282
12283 if ($OE === 'E') {
12284 if ($Hhtml) {
12285 $this->HTMLHeaderE = [];
12286 $this->HTMLHeaderE['html'] = $Hhtml;
12287 $this->HTMLHeaderE['h'] = $height;
12288 } else {
12289 $this->HTMLHeaderE = '';
12290 }
12291 } else {
12292 if ($Hhtml) {
12293 $this->HTMLHeader = [];
12294 $this->HTMLHeader['html'] = $Hhtml;
12295 $this->HTMLHeader['h'] = $height;
12296 } else {
12297 $this->HTMLHeader = '';
12298 }
12299 }
12300
12301 if (!$this->mirrorMargins && $OE == 'E') {
12302 return;
12303 }
12304 if ($Hhtml == '') {
12305 return;
12306 }
12307
12308 if ($this->setAutoTopMargin == 'pad') {
12309 $this->tMargin = $this->margin_header + $height + $this->orig_tMargin;
12310 if (isset($this->saveHTMLHeader[$this->page][$OE]['mt'])) {
12311 $this->saveHTMLHeader[$this->page][$OE]['mt'] = $this->tMargin;
12312 }
12313 } elseif ($this->setAutoTopMargin == 'stretch') {
12314 $this->tMargin = max($this->orig_tMargin, $this->margin_header + $height + $this->autoMarginPadding);
12315 if (isset($this->saveHTMLHeader[$this->page][$OE]['mt'])) {
12316 $this->saveHTMLHeader[$this->page][$OE]['mt'] = $this->tMargin;
12317 }
12318 }
12319 if ($write && $this->state != 0 && (($this->mirrorMargins && $OE == 'E' && ($this->page) % 2 == 0) || ($this->mirrorMargins && $OE != 'E' && ($this->page) % 2 == 1) || !$this->mirrorMargins)) {
12320 $this->writeHTMLHeaders();
12321 }
12322 }
12323
12324 function SetHTMLFooter($footer = '', $OE = '')
12325 {
12326 $height = 0;
12327 if (is_array($footer) && isset($footer['html']) && $footer['html']) {
12328 $Fhtml = $footer['html'];
12329 if ($this->setAutoBottomMargin) {
12330 if (isset($footer['h'])) {
12331 $height = $footer['h'];
12332 } else {
12333 $height = $this->_getHtmlHeight($Fhtml);
12334 }
12335 }
12336 } elseif (!is_array($footer) && $footer) {
12337 $Fhtml = $footer;
12338 if ($this->setAutoBottomMargin) {
12339 $height = $this->_getHtmlHeight($Fhtml);
12340 }
12341 } else {
12342 $Fhtml = '';
12343 }
12344
12345 if ($OE !== 'E') {
12346 $OE = 'O';
12347 }
12348
12349 if ($OE === 'E') {
12350 if ($Fhtml) {
12351 $this->HTMLFooterE = [];
12352 $this->HTMLFooterE['html'] = $Fhtml;
12353 $this->HTMLFooterE['h'] = $height;
12354 } else {
12355 $this->HTMLFooterE = '';
12356 }
12357 } else {
12358 if ($Fhtml) {
12359 $this->HTMLFooter = [];
12360 $this->HTMLFooter['html'] = $Fhtml;
12361 $this->HTMLFooter['h'] = $height;
12362 } else {
12363 $this->HTMLFooter = '';
12364 }
12365 }
12366
12367 if (!$this->mirrorMargins && $OE == 'E') {
12368 return;
12369 }
12370
12371 if ($Fhtml == '') {
12372 return false;
12373 }
12374
12375 if ($this->setAutoBottomMargin == 'pad') {
12376 $this->bMargin = $this->margin_footer + $height + $this->orig_bMargin;
12377 $this->PageBreakTrigger = $this->h - $this->bMargin;
12378 if (isset($this->saveHTMLHeader[$this->page][$OE]['mb'])) {
12379 $this->saveHTMLHeader[$this->page][$OE]['mb'] = $this->bMargin;
12380 }
12381 } elseif ($this->setAutoBottomMargin == 'stretch') {
12382 $this->bMargin = max($this->orig_bMargin, $this->margin_footer + $height + $this->autoMarginPadding);
12383 $this->PageBreakTrigger = $this->h - $this->bMargin;
12384 if (isset($this->saveHTMLHeader[$this->page][$OE]['mb'])) {
12385 $this->saveHTMLHeader[$this->page][$OE]['mb'] = $this->bMargin;
12386 }
12387 }
12388 }
12389
12391 {
12392 $save_state = $this->state;
12393 if ($this->state == 0) {
12394 $this->AddPage($this->CurOrientation);
12395 }
12396 $this->state = 2;
12397 $this->Reset();
12398 $this->pageoutput[$this->page] = [];
12399 $save_x = $this->x;
12400 $save_y = $this->y;
12401 $this->x = $this->lMargin;
12402 $this->y = $this->margin_header;
12403
12404 // Replace of page number aliases and date format
12405 $pnstr = $this->pagenumPrefix . $this->docPageNum($this->page) . $this->pagenumSuffix;
12406 $pntstr = $this->nbpgPrefix . $this->docPageNumTotal($this->page) . $this->nbpgSuffix;
12407 $nb = $this->page;
12408 $html = $this->aliasReplace($html, $pnstr, $pntstr, $nb);
12409
12410 $this->HTMLheaderPageLinks = [];
12411 $this->HTMLheaderPageAnnots = [];
12412 $this->HTMLheaderPageForms = [];
12413 $savepb = $this->pageBackgrounds;
12414 $this->writingHTMLheader = true;
12415 $this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
12416 $this->writingHTMLheader = false;
12417 $h = ($this->y - $this->margin_header);
12418 $this->Reset();
12419
12420 // mPDF 5.7.2 - Clear in case Float used in Header/Footer
12421 $this->blk[0]['blockContext'] = 0;
12422 $this->blk[0]['float_endpos'] = 0;
12423
12424 $this->pageoutput[$this->page] = [];
12425 $this->headerbuffer = '';
12426 $this->pageBackgrounds = $savepb;
12427 $this->x = $save_x;
12428 $this->y = $save_y;
12429 $this->state = $save_state;
12430
12431 if ($save_state == 0) {
12432 unset($this->pages[1]);
12433 $this->page = 0;
12434 }
12435 return $h;
12436 }
12437
12438 // Called internally from Header
12440 {
12441
12442 if ($this->mirrorMargins && ($this->page) % 2 == 0) {
12443 $OE = 'E';
12444 } else {
12445 $OE = 'O';
12446 }
12447
12448 if ($OE === 'E') {
12449 $this->saveHTMLHeader[$this->page][$OE]['html'] = $this->HTMLHeaderE['html'];
12450 } else {
12451 $this->saveHTMLHeader[$this->page][$OE]['html'] = $this->HTMLHeader['html'];
12452 }
12453
12454 if ($this->forcePortraitHeaders && $this->CurOrientation == 'L' && $this->CurOrientation != $this->DefOrientation) {
12455 $this->saveHTMLHeader[$this->page][$OE]['rotate'] = true;
12456 $this->saveHTMLHeader[$this->page][$OE]['ml'] = $this->tMargin;
12457 $this->saveHTMLHeader[$this->page][$OE]['mr'] = $this->bMargin;
12458 $this->saveHTMLHeader[$this->page][$OE]['mh'] = $this->margin_header;
12459 $this->saveHTMLHeader[$this->page][$OE]['mf'] = $this->margin_footer;
12460 $this->saveHTMLHeader[$this->page][$OE]['pw'] = $this->h;
12461 $this->saveHTMLHeader[$this->page][$OE]['ph'] = $this->w;
12462 } else {
12463 $this->saveHTMLHeader[$this->page][$OE]['ml'] = $this->lMargin;
12464 $this->saveHTMLHeader[$this->page][$OE]['mr'] = $this->rMargin;
12465 $this->saveHTMLHeader[$this->page][$OE]['mh'] = $this->margin_header;
12466 $this->saveHTMLHeader[$this->page][$OE]['mf'] = $this->margin_footer;
12467 $this->saveHTMLHeader[$this->page][$OE]['pw'] = $this->w;
12468 $this->saveHTMLHeader[$this->page][$OE]['ph'] = $this->h;
12469 }
12470 }
12471
12473 {
12474
12475 if ($this->mirrorMargins && ($this->page) % 2 == 0) {
12476 $OE = 'E';
12477 } else {
12478 $OE = 'O';
12479 }
12480
12481 if ($OE === 'E') {
12482 $this->saveHTMLFooter[$this->page][$OE]['html'] = $this->HTMLFooterE['html'];
12483 } else {
12484 $this->saveHTMLFooter[$this->page][$OE]['html'] = $this->HTMLFooter['html'];
12485 }
12486
12487 if ($this->forcePortraitHeaders && $this->CurOrientation == 'L' && $this->CurOrientation != $this->DefOrientation) {
12488 $this->saveHTMLFooter[$this->page][$OE]['rotate'] = true;
12489 $this->saveHTMLFooter[$this->page][$OE]['ml'] = $this->tMargin;
12490 $this->saveHTMLFooter[$this->page][$OE]['mr'] = $this->bMargin;
12491 $this->saveHTMLFooter[$this->page][$OE]['mt'] = $this->rMargin;
12492 $this->saveHTMLFooter[$this->page][$OE]['mb'] = $this->lMargin;
12493 $this->saveHTMLFooter[$this->page][$OE]['mh'] = $this->margin_header;
12494 $this->saveHTMLFooter[$this->page][$OE]['mf'] = $this->margin_footer;
12495 $this->saveHTMLFooter[$this->page][$OE]['pw'] = $this->h;
12496 $this->saveHTMLFooter[$this->page][$OE]['ph'] = $this->w;
12497 } else {
12498 $this->saveHTMLFooter[$this->page][$OE]['ml'] = $this->lMargin;
12499 $this->saveHTMLFooter[$this->page][$OE]['mr'] = $this->rMargin;
12500 $this->saveHTMLFooter[$this->page][$OE]['mt'] = $this->tMargin;
12501 $this->saveHTMLFooter[$this->page][$OE]['mb'] = $this->bMargin;
12502 $this->saveHTMLFooter[$this->page][$OE]['mh'] = $this->margin_header;
12503 $this->saveHTMLFooter[$this->page][$OE]['mf'] = $this->margin_footer;
12504 $this->saveHTMLFooter[$this->page][$OE]['pw'] = $this->w;
12505 $this->saveHTMLFooter[$this->page][$OE]['ph'] = $this->h;
12506 }
12507 }
12508
12509 // mPDF 6
12510 function _shareHeaderFooterWidth($cl, $cc, $cr)
12511 {
12512 // mPDF 6
12513 $l = mb_strlen($cl, 'UTF-8');
12514 $c = mb_strlen($cc, 'UTF-8');
12515 $r = mb_strlen($cr, 'UTF-8');
12516 $s = max($l, $r);
12517 $tw = $c + 2 * $s;
12518 if ($tw > 0) {
12519 return [intval($s * 100 / $tw), intval($c * 100 / $tw), intval($s * 100 / $tw)];
12520 } else {
12521 return [33, 33, 33];
12522 }
12523 }
12524
12525 // mPDF 6
12526 // Create an HTML header/footer from array (non-HTML header/footer)
12527 function _createHTMLheaderFooter($arr, $hf)
12528 {
12529 $lContent = (isset($arr['L']['content']) ? $arr['L']['content'] : '');
12530 $cContent = (isset($arr['C']['content']) ? $arr['C']['content'] : '');
12531 $rContent = (isset($arr['R']['content']) ? $arr['R']['content'] : '');
12532
12533 list($lw, $cw, $rw) = $this->_shareHeaderFooterWidth($lContent, $cContent, $rContent);
12534
12535 if ($hf == 'H') {
12536 $valign = 'bottom';
12537 $vpadding = '0 0 ' . $this->header_line_spacing . 'em 0';
12538 } else {
12539 $valign = 'top';
12540 $vpadding = '' . $this->footer_line_spacing . 'em 0 0 0';
12541 }
12542
12543 if ($this->directionality == 'rtl') { // table columns get reversed so need different text-alignment
12544 $talignL = 'right';
12545 $talignR = 'left';
12546 } else {
12547 $talignL = 'left';
12548 $talignR = 'right';
12549 }
12550
12551 $html = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: ' . $valign . '; color: #000000; ';
12552
12553 if (isset($arr['line']) && $arr['line']) {
12554 $html .= ' border-' . $valign . ': 0.1mm solid #000000;';
12555 }
12556
12557 $html .= '">';
12558 $html .= '<tr>';
12559 $html .= '<td width="' . $lw . '%" style="padding: ' . $vpadding . '; text-align: ' . $talignL . '; ';
12560
12561 if (isset($arr['L']['font-family'])) {
12562 $html .= ' font-family: ' . $arr['L']['font-family'] . ';';
12563 }
12564
12565 if (isset($arr['L']['color'])) {
12566 $html .= ' color: ' . $arr['L']['color'] . ';';
12567 }
12568
12569 if (isset($arr['L']['font-size'])) {
12570 $html .= ' font-size: ' . $arr['L']['font-size'] . 'pt;';
12571 }
12572
12573 if (isset($arr['L']['font-style'])) {
12574 if ($arr['L']['font-style'] == 'B' || $arr['L']['font-style'] == 'BI') {
12575 $html .= ' font-weight: bold;';
12576 }
12577 if ($arr['L']['font-style'] == 'I' || $arr['L']['font-style'] == 'BI') {
12578 $html .= ' font-style: italic;';
12579 }
12580 }
12581
12582 $html .= '">' . $lContent . '</td>';
12583 $html .= '<td width="' . $cw . '%" style="padding: ' . $vpadding . '; text-align: center; ';
12584
12585 if (isset($arr['C']['font-family'])) {
12586 $html .= ' font-family: ' . $arr['C']['font-family'] . ';';
12587 }
12588
12589 if (isset($arr['C']['color'])) {
12590 $html .= ' color: ' . $arr['C']['color'] . ';';
12591 }
12592
12593 if (isset($arr['C']['font-size'])) {
12594 $html .= ' font-size: ' . $arr['C']['font-size'] . 'pt;';
12595 }
12596
12597 if (isset($arr['C']['font-style'])) {
12598 if ($arr['C']['font-style'] == 'B' || $arr['C']['font-style'] == 'BI') {
12599 $html .= ' font-weight: bold;';
12600 }
12601 if ($arr['C']['font-style'] == 'I' || $arr['C']['font-style'] == 'BI') {
12602 $html .= ' font-style: italic;';
12603 }
12604 }
12605
12606 $html .= '">' . $cContent . '</td>';
12607 $html .= '<td width="' . $rw . '%" style="padding: ' . $vpadding . '; text-align: ' . $talignR . '; ';
12608
12609 if (isset($arr['R']['font-family'])) {
12610 $html .= ' font-family: ' . $arr['R']['font-family'] . ';';
12611 }
12612
12613 if (isset($arr['R']['color'])) {
12614 $html .= ' color: ' . $arr['R']['color'] . ';';
12615 }
12616
12617 if (isset($arr['R']['font-size'])) {
12618 $html .= ' font-size: ' . $arr['R']['font-size'] . 'pt;';
12619 }
12620
12621 if (isset($arr['R']['font-style'])) {
12622 if ($arr['R']['font-style'] == 'B' || $arr['R']['font-style'] == 'BI') {
12623 $html .= ' font-weight: bold;';
12624 }
12625 if ($arr['R']['font-style'] == 'I' || $arr['R']['font-style'] == 'BI') {
12626 $html .= ' font-style: italic;';
12627 }
12628 }
12629
12630 $html .= '">' . $rContent . '</td>';
12631 $html .= '</tr></table>';
12632
12633 return $html;
12634 }
12635
12636 function DefHeaderByName($name, $arr)
12637 {
12638 if (!$name) {
12639 $name = '_nonhtmldefault';
12640 }
12641 $html = $this->_createHTMLheaderFooter($arr, 'H');
12642
12643 $this->pageHTMLheaders[$name]['html'] = $html;
12644 $this->pageHTMLheaders[$name]['h'] = $this->_getHtmlHeight($html);
12645 }
12646
12647 function DefFooterByName($name, $arr)
12648 {
12649 if (!$name) {
12650 $name = '_nonhtmldefault';
12651 }
12652 $html = $this->_createHTMLheaderFooter($arr, 'F');
12653
12654 $this->pageHTMLfooters[$name]['html'] = $html;
12655 $this->pageHTMLfooters[$name]['h'] = $this->_getHtmlHeight($html);
12656 }
12657
12658 function SetHeaderByName($name, $side = 'O', $write = false)
12659 {
12660 if (!$name) {
12661 $name = '_nonhtmldefault';
12662 }
12663 $this->SetHTMLHeader($this->pageHTMLheaders[$name], $side, $write);
12664 }
12665
12666 function SetFooterByName($name, $side = 'O')
12667 {
12668 if (!$name) {
12669 $name = '_nonhtmldefault';
12670 }
12671 $this->SetHTMLFooter($this->pageHTMLfooters[$name], $side);
12672 }
12673
12675 {
12676 if (!$name) {
12677 $name = '_default';
12678 }
12679
12680 $this->pageHTMLheaders[$name]['html'] = $html;
12681 $this->pageHTMLheaders[$name]['h'] = $this->_getHtmlHeight($html);
12682 }
12683
12685 {
12686 if (!$name) {
12687 $name = '_default';
12688 }
12689
12690 $this->pageHTMLfooters[$name]['html'] = $html;
12691 $this->pageHTMLfooters[$name]['h'] = $this->_getHtmlHeight($html);
12692 }
12693
12694 function SetHTMLHeaderByName($name, $side = 'O', $write = false)
12695 {
12696 if (!$name) {
12697 $name = '_default';
12698 }
12699 $this->SetHTMLHeader($this->pageHTMLheaders[$name], $side, $write);
12700 }
12701
12702 function SetHTMLFooterByName($name, $side = 'O')
12703 {
12704 if (!$name) {
12705 $name = '_default';
12706 }
12707 $this->SetHTMLFooter($this->pageHTMLfooters[$name], $side);
12708 }
12709
12710 function SetHeader($Harray = [], $side = '', $write = false)
12711 {
12712 $oddhtml = '';
12713 $evenhtml = '';
12714
12715 if (is_string($Harray)) {
12716
12717 if (strlen($Harray) === 0) {
12718
12719 $oddhtml = '';
12720 $evenhtml = '';
12721
12722 } elseif (strpos($Harray, '|') !== false) {
12723
12724 $hdet = explode('|', $Harray);
12725
12726 list($lw, $cw, $rw) = $this->_shareHeaderFooterWidth($hdet[0], $hdet[1], $hdet[2]);
12727 $oddhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: bottom; color: #000000; ';
12728
12729 if ($this->defaultheaderfontsize) {
12730 $oddhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
12731 }
12732
12733 if ($this->defaultheaderfontstyle) {
12734
12735 if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
12736 $oddhtml .= ' font-weight: bold;';
12737 }
12738
12739 if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
12740 $oddhtml .= ' font-style: italic;';
12741 }
12742 }
12743
12744 if ($this->defaultheaderline) {
12745 $oddhtml .= ' border-bottom: 0.1mm solid #000000;';
12746 }
12747
12748 $oddhtml .= '">';
12749 $oddhtml .= '<tr>';
12750 $oddhtml .= '<td width="' . $lw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: left; ">' . $hdet[0] . '</td>';
12751 $oddhtml .= '<td width="' . $cw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: center; ">' . $hdet[1] . '</td>';
12752 $oddhtml .= '<td width="' . $rw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: right; ">' . $hdet[2] . '</td>';
12753 $oddhtml .= '</tr></table>';
12754
12755 $evenhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: bottom; color: #000000; ';
12756
12757 if ($this->defaultheaderfontsize) {
12758 $evenhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
12759 }
12760
12761 if ($this->defaultheaderfontstyle) {
12762 if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
12763 $evenhtml .= ' font-weight: bold;';
12764 }
12765 if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
12766 $evenhtml .= ' font-style: italic;';
12767 }
12768 }
12769
12770 if ($this->defaultheaderline) {
12771 $evenhtml .= ' border-bottom: 0.1mm solid #000000;';
12772 }
12773
12774 $evenhtml .= '">';
12775 $evenhtml .= '<tr>';
12776 $evenhtml .= '<td width="' . $rw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: left; ">' . $hdet[2] . '</td>';
12777 $evenhtml .= '<td width="' . $cw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: center; ">' . $hdet[1] . '</td>';
12778 $evenhtml .= '<td width="' . $lw . '%" style="padding: 0 0 ' . $this->header_line_spacing . 'em 0; text-align: right; ">' . $hdet[0] . '</td>';
12779 $evenhtml .= '</tr></table>';
12780
12781 } else {
12782
12783 $oddhtml = '<div style="margin: 0; color: #000000; ';
12784
12785 if ($this->defaultheaderfontsize) {
12786 $oddhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
12787 }
12788
12789 if ($this->defaultheaderfontstyle) {
12790
12791 if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
12792 $oddhtml .= ' font-weight: bold;';
12793 }
12794
12795 if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
12796 $oddhtml .= ' font-style: italic;';
12797 }
12798 }
12799
12800 if ($this->defaultheaderline) {
12801 $oddhtml .= ' border-bottom: 0.1mm solid #000000;';
12802 }
12803
12804 $oddhtml .= 'text-align: right; ">' . $Harray . '</div>';
12805 $evenhtml = '<div style="margin: 0; color: #000000; ';
12806
12807 if ($this->defaultheaderfontsize) {
12808 $evenhtml .= ' font-size: ' . $this->defaultheaderfontsize . 'pt;';
12809 }
12810
12811 if ($this->defaultheaderfontstyle) {
12812
12813 if ($this->defaultheaderfontstyle == 'B' || $this->defaultheaderfontstyle == 'BI') {
12814 $evenhtml .= ' font-weight: bold;';
12815 }
12816
12817 if ($this->defaultheaderfontstyle == 'I' || $this->defaultheaderfontstyle == 'BI') {
12818 $evenhtml .= ' font-style: italic;';
12819 }
12820 }
12821
12822 if ($this->defaultheaderline) {
12823 $evenhtml .= ' border-bottom: 0.1mm solid #000000;';
12824 }
12825
12826 $evenhtml .= 'text-align: left; ">' . $Harray . '</div>';
12827 }
12828
12829 } elseif (is_array($Harray) && !empty($Harray)) {
12830
12831 $odd = null;
12832 $even = null;
12833
12834 if ($side === 'O') {
12835 $odd = $Harray;
12836 } elseif ($side === 'E') {
12837 $even = $Harray;
12838 } else {
12839 $odd = Arrays::get($Harray, 'odd', null);
12840 $even = Arrays::get($Harray, 'even', null);
12841 }
12842
12843 $oddhtml = $this->_createHTMLheaderFooter($odd, 'H');
12844 $evenhtml = $this->_createHTMLheaderFooter($even, 'H');
12845 }
12846
12847 if ($side === 'E') {
12848 $this->SetHTMLHeader($evenhtml, 'E', $write);
12849 } elseif ($side === 'O') {
12850 $this->SetHTMLHeader($oddhtml, 'O', $write);
12851 } else {
12852 $this->SetHTMLHeader($oddhtml, 'O', $write);
12853 $this->SetHTMLHeader($evenhtml, 'E', $write);
12854 }
12855 }
12856
12857 function SetFooter($Farray = [], $side = '')
12858 {
12859 $oddhtml = '';
12860 $evenhtml = '';
12861
12862 if (is_string($Farray)) {
12863
12864 if (strlen($Farray) == 0) {
12865
12866 $oddhtml = '';
12867 $evenhtml = '';
12868
12869 } elseif (strpos($Farray, '|') !== false) {
12870
12871 $hdet = explode('|', $Farray);
12872 $oddhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: top; color: #000000; ';
12873
12874 if ($this->defaultfooterfontsize) {
12875 $oddhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
12876 }
12877
12878 if ($this->defaultfooterfontstyle) {
12879 if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
12880 $oddhtml .= ' font-weight: bold;';
12881 }
12882 if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
12883 $oddhtml .= ' font-style: italic;';
12884 }
12885 }
12886
12887 if ($this->defaultfooterline) {
12888 $oddhtml .= ' border-top: 0.1mm solid #000000;';
12889 }
12890
12891 $oddhtml .= '">';
12892 $oddhtml .= '<tr>';
12893 $oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: left; ">' . $hdet[0] . '</td>';
12894 $oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: center; ">' . $hdet[1] . '</td>';
12895 $oddhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: right; ">' . $hdet[2] . '</td>';
12896 $oddhtml .= '</tr></table>';
12897
12898 $evenhtml = '<table width="100%" style="border-collapse: collapse; margin: 0; vertical-align: top; color: #000000; ';
12899
12900 if ($this->defaultfooterfontsize) {
12901 $evenhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
12902 }
12903
12904 if ($this->defaultfooterfontstyle) {
12905
12906 if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
12907 $evenhtml .= ' font-weight: bold;';
12908 }
12909
12910 if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
12911 $evenhtml .= ' font-style: italic;';
12912 }
12913 }
12914
12915 if ($this->defaultfooterline) {
12916 $evenhtml .= ' border-top: 0.1mm solid #000000;';
12917 }
12918
12919 $evenhtml .= '">';
12920 $evenhtml .= '<tr>';
12921 $evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: left; ">' . $hdet[2] . '</td>';
12922 $evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: center; ">' . $hdet[1] . '</td>';
12923 $evenhtml .= '<td width="33%" style="padding: ' . $this->footer_line_spacing . 'em 0 0 0; text-align: right; ">' . $hdet[0] . '</td>';
12924 $evenhtml .= '</tr></table>';
12925
12926 } else {
12927
12928 $oddhtml = '<div style="margin: 0; color: #000000; ';
12929
12930 if ($this->defaultfooterfontsize) {
12931 $oddhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
12932 }
12933
12934 if ($this->defaultfooterfontstyle) {
12935
12936 if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
12937 $oddhtml .= ' font-weight: bold;';
12938 }
12939
12940 if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
12941 $oddhtml .= ' font-style: italic;';
12942 }
12943 }
12944
12945 if ($this->defaultfooterline) {
12946 $oddhtml .= ' border-top: 0.1mm solid #000000;';
12947 }
12948
12949 $oddhtml .= 'text-align: right; ">' . $Farray . '</div>';
12950
12951 $evenhtml = '<div style="margin: 0; color: #000000; ';
12952
12953 if ($this->defaultfooterfontsize) {
12954 $evenhtml .= ' font-size: ' . $this->defaultfooterfontsize . 'pt;';
12955 }
12956
12957 if ($this->defaultfooterfontstyle) {
12958
12959 if ($this->defaultfooterfontstyle == 'B' || $this->defaultfooterfontstyle == 'BI') {
12960 $evenhtml .= ' font-weight: bold;';
12961 }
12962
12963 if ($this->defaultfooterfontstyle == 'I' || $this->defaultfooterfontstyle == 'BI') {
12964 $evenhtml .= ' font-style: italic;';
12965 }
12966 }
12967
12968 if ($this->defaultfooterline) {
12969 $evenhtml .= ' border-top: 0.1mm solid #000000;';
12970 }
12971
12972 $evenhtml .= 'text-align: left; ">' . $Farray . '</div>';
12973 }
12974
12975 } elseif (is_array($Farray)) {
12976
12977 $odd = null;
12978 $even = null;
12979
12980 if ($side === 'O') {
12981 $odd = $Farray;
12982 } elseif ($side == 'E') {
12983 $even = $Farray;
12984 } else {
12985 $odd = Arrays::get($Farray, 'odd', null);
12986 $even = Arrays::get($Farray, 'even', null);
12987 }
12988
12989 $oddhtml = $this->_createHTMLheaderFooter($odd, 'F');
12990 $evenhtml = $this->_createHTMLheaderFooter($even, 'F');
12991 }
12992
12993 if ($side === 'E') {
12994 $this->SetHTMLFooter($evenhtml, 'E');
12995 } elseif ($side === 'O') {
12996 $this->SetHTMLFooter($oddhtml, 'O');
12997 } else {
12998 $this->SetHTMLFooter($oddhtml, 'O');
12999 $this->SetHTMLFooter($evenhtml, 'E');
13000 }
13001 }
13002
13003 /* -- WATERMARK -- */
13004
13005 function SetWatermarkText($txt = '', $alpha = -1)
13006 {
13007 if ($alpha >= 0) {
13008 $this->watermarkTextAlpha = $alpha;
13009 }
13010 $this->watermarkText = $txt;
13011 }
13012
13013 function SetWatermarkImage($src, $alpha = -1, $size = 'D', $pos = 'F')
13014 {
13015 if ($alpha >= 0) {
13016 $this->watermarkImageAlpha = $alpha;
13017 }
13018 $this->watermarkImage = $src;
13019 $this->watermark_size = $size;
13020 $this->watermark_pos = $pos;
13021 }
13022
13023 /* -- END WATERMARK -- */
13024
13025 // Page footer
13026 function Footer()
13027 {
13028 /* -- CSS-PAGE -- */
13029 // PAGED MEDIA - CROP / CROSS MARKS from @PAGE
13030 if ($this->show_marks == 'CROP' || $this->show_marks == 'CROPCROSS') {
13031 // Show TICK MARKS
13032 $this->SetLineWidth(0.1); // = 0.1 mm
13033 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
13034 $l = $this->cropMarkLength;
13035 $m = $this->cropMarkMargin; // Distance of crop mark from margin
13036 $b = $this->nonPrintMargin; // Non-printable border at edge of paper sheet
13037 $ax1 = $b;
13038 $bx = $this->page_box['outer_width_LR'] - $m;
13039 $ax = max($ax1, $bx - $l);
13040 $cx1 = $this->w - $b;
13041 $dx = $this->w - $this->page_box['outer_width_LR'] + $m;
13042 $cx = min($cx1, $dx + $l);
13043 $ay1 = $b;
13044 $by = $this->page_box['outer_width_TB'] - $m;
13045 $ay = max($ay1, $by - $l);
13046 $cy1 = $this->h - $b;
13047 $dy = $this->h - $this->page_box['outer_width_TB'] + $m;
13048 $cy = min($cy1, $dy + $l);
13049
13050 $this->Line($ax, $this->page_box['outer_width_TB'], $bx, $this->page_box['outer_width_TB']);
13051 $this->Line($cx, $this->page_box['outer_width_TB'], $dx, $this->page_box['outer_width_TB']);
13052 $this->Line($ax, $this->h - $this->page_box['outer_width_TB'], $bx, $this->h - $this->page_box['outer_width_TB']);
13053 $this->Line($cx, $this->h - $this->page_box['outer_width_TB'], $dx, $this->h - $this->page_box['outer_width_TB']);
13054 $this->Line($this->page_box['outer_width_LR'], $ay, $this->page_box['outer_width_LR'], $by);
13055 $this->Line($this->page_box['outer_width_LR'], $cy, $this->page_box['outer_width_LR'], $dy);
13056 $this->Line($this->w - $this->page_box['outer_width_LR'], $ay, $this->w - $this->page_box['outer_width_LR'], $by);
13057 $this->Line($this->w - $this->page_box['outer_width_LR'], $cy, $this->w - $this->page_box['outer_width_LR'], $dy);
13058
13059 if ($this->printers_info) {
13060 $hd = date('Y-m-d H:i') . ' Page ' . $this->page . ' of {nb}';
13061 $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
13062 $this->SetFont('arial', '', 7.5, true, true);
13063 $this->x = $this->page_box['outer_width_LR'] + 1.5;
13064 $this->y = 1;
13065 $this->Cell(0, $this->FontSize, $hd, 0, 0, 'L', 0, '', 0, 0, 0, 'M');
13066 $this->SetFont($this->default_font, '', $this->original_default_font_size);
13067 }
13068 }
13069 if ($this->show_marks == 'CROSS' || $this->show_marks == 'CROPCROSS') {
13070 $this->SetLineWidth(0.1); // = 0.1 mm
13071 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
13072 $l = 14 / 2; // longer length of the cross line (half)
13073 $w = 6 / 2; // shorter width of the cross line (half)
13074 $r = 1.2; // radius of circle
13075 $m = $this->crossMarkMargin; // Distance of cross mark from margin
13076 $x1 = $this->page_box['outer_width_LR'] - $m;
13077 $x2 = $this->w - $this->page_box['outer_width_LR'] + $m;
13078 $y1 = $this->page_box['outer_width_TB'] - $m;
13079 $y2 = $this->h - $this->page_box['outer_width_TB'] + $m;
13080 // Left
13081 $this->Circle($x1, $this->h / 2, $r, 'S');
13082 $this->Line($x1 - $w, $this->h / 2, $x1 + $w, $this->h / 2);
13083 $this->Line($x1, $this->h / 2 - $l, $x1, $this->h / 2 + $l);
13084 // Right
13085 $this->Circle($x2, $this->h / 2, $r, 'S');
13086 $this->Line($x2 - $w, $this->h / 2, $x2 + $w, $this->h / 2);
13087 $this->Line($x2, $this->h / 2 - $l, $x2, $this->h / 2 + $l);
13088 // Top
13089 $this->Circle($this->w / 2, $y1, $r, 'S');
13090 $this->Line($this->w / 2, $y1 - $w, $this->w / 2, $y1 + $w);
13091 $this->Line($this->w / 2 - $l, $y1, $this->w / 2 + $l, $y1);
13092 // Bottom
13093 $this->Circle($this->w / 2, $y2, $r, 'S');
13094 $this->Line($this->w / 2, $y2 - $w, $this->w / 2, $y2 + $w);
13095 $this->Line($this->w / 2 - $l, $y2, $this->w / 2 + $l, $y2);
13096 }
13097
13098 /* -- END CSS-PAGE -- */
13099
13100 // mPDF 6
13101 // If @page set non-HTML headers/footers named, they were not read until later in the HTML code - so now set them
13102 if ($this->page == 1) {
13103 if ($this->firstPageBoxHeader) {
13104 if (isset($this->pageHTMLheaders[$this->firstPageBoxHeader])) {
13105 $this->HTMLHeader = $this->pageHTMLheaders[$this->firstPageBoxHeader];
13106 }
13107 $this->Header();
13108 }
13109 if ($this->firstPageBoxFooter) {
13110 if (isset($this->pageHTMLfooters[$this->firstPageBoxFooter])) {
13111 $this->HTMLFooter = $this->pageHTMLfooters[$this->firstPageBoxFooter];
13112 }
13113 }
13114 $this->firstPageBoxHeader = '';
13115 $this->firstPageBoxFooter = '';
13116 }
13117
13118
13119 if (($this->mirrorMargins && ($this->page % 2 == 0) && $this->HTMLFooterE) || ($this->mirrorMargins && ($this->page % 2 == 1) && $this->HTMLFooter) || (!$this->mirrorMargins && $this->HTMLFooter)) {
13120 $this->writeHTMLFooters();
13121 }
13122
13123 /* -- WATERMARK -- */
13124 if (($this->watermarkText) && ($this->showWatermarkText)) {
13125 $this->watermark($this->watermarkText, $this->watermarkAngle, 120, $this->watermarkTextAlpha); // Watermark text
13126 }
13127 if (($this->watermarkImage) && ($this->showWatermarkImage)) {
13128 $this->watermarkImg($this->watermarkImage, $this->watermarkImageAlpha); // Watermark image
13129 }
13130 /* -- END WATERMARK -- */
13131 }
13132
13133 /* -- HTML-CSS -- */
13134
13145 function WriteHTML($html, $mode = HTMLParserMode::DEFAULT_MODE, $init = true, $close = true)
13146 {
13147 /* Check $html is an integer, float, string, boolean or class with __toString(), otherwise throw exception */
13148 if (is_scalar($html) === false) {
13149 if (!is_object($html) || ! method_exists($html, '__toString')) {
13150 throw new \Mpdf\MpdfException('WriteHTML() requires $html be an integer, float, string, boolean or an object with the __toString() magic method.');
13151 }
13152 }
13153
13154 // Check the mode is valid
13155 if (in_array($mode, HTMLParserMode::getAllModes(), true) === false) {
13156 throw new \Mpdf\MpdfException('WriteHTML() requires $mode to be one of the modes defined in HTMLParserMode');
13157 }
13158
13159 /* Cast $html as a string */
13160 $html = (string) $html;
13161
13162 // @log Parsing CSS & Headers
13163
13164 if ($init) {
13165 $this->headerbuffer = '';
13166 $this->textbuffer = [];
13167 $this->fixedPosBlockSave = [];
13168 }
13169 if ($mode === HTMLParserMode::HEADER_CSS) {
13170 $html = '<style> ' . $html . ' </style>';
13171 } // stylesheet only
13172
13173 if ($this->allow_charset_conversion) {
13174 if ($mode === HTMLParserMode::DEFAULT_MODE) {
13175 $this->ReadCharset($html);
13176 }
13177 if ($this->charset_in && $mode !== HTMLParserMode::HTML_HEADER_BUFFER) {
13178 $success = iconv($this->charset_in, 'UTF-8//TRANSLIT', $html);
13179 if ($success) {
13180 $html = $success;
13181 }
13182 }
13183 }
13184
13185 $html = $this->purify_utf8($html, false);
13186 if ($init) {
13187 $this->blklvl = 0;
13188 $this->lastblocklevelchange = 0;
13189 $this->blk = [];
13190 $this->initialiseBlock($this->blk[0]);
13191 $this->blk[0]['width'] = & $this->pgwidth;
13192 $this->blk[0]['inner_width'] = & $this->pgwidth;
13193 $this->blk[0]['blockContext'] = $this->blockContext;
13194 }
13195
13196 $zproperties = [];
13197 if ($mode === HTMLParserMode::DEFAULT_MODE || $mode === HTMLParserMode::HEADER_CSS) {
13198 $this->ReadMetaTags($html);
13199
13200 if (preg_match('/<base[^>]*href=["\']([^"\'>]*)["\']/i', $html, $m)) {
13201 $this->SetBasePath($m[1]);
13202 }
13203 $html = $this->cssManager->ReadCSS($html);
13204
13205 if ($this->autoLangToFont && !$this->usingCoreFont && preg_match('/<html [^>]*lang=[\'\"](.*?)[\'\"]/ism', $html, $m)) {
13206 $html_lang = $m[1];
13207 }
13208
13209 if (preg_match('/<html [^>]*dir=[\'\"]\s*rtl\s*[\'\"]/ism', $html)) {
13210 $zproperties['DIRECTION'] = 'rtl';
13211 }
13212
13213 // allow in-line CSS for body tag to be parsed // Get <body> tag inline CSS
13214 if (preg_match('/<body([^>]*)>(.*?)<\/body>/ism', $html, $m) || preg_match('/<body([^>]*)>(.*)$/ism', $html, $m)) {
13215 $html = $m[2];
13216 // Changed to allow style="background: url('bg.jpg')"
13217 if (preg_match('/style=[\"](.*?)[\"]/ism', $m[1], $mm) || preg_match('/style=[\'](.*?)[\']/ism', $m[1], $mm)) {
13218 $zproperties = $this->cssManager->readInlineCSS($mm[1]);
13219 }
13220 if (preg_match('/dir=[\'\"]\s*rtl\s*[\'\"]/ism', $m[1])) {
13221 $zproperties['DIRECTION'] = 'rtl';
13222 }
13223 if (isset($html_lang) && $html_lang) {
13224 $zproperties['LANG'] = $html_lang;
13225 }
13226 if ($this->autoLangToFont && !$this->onlyCoreFonts && preg_match('/lang=[\'\"](.*?)[\'\"]/ism', $m[1], $mm)) {
13227 $zproperties['LANG'] = $mm[1];
13228 }
13229 }
13230 }
13231 $properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', '');
13232 if ($zproperties) {
13233 $properties = $this->cssManager->array_merge_recursive_unique($properties, $zproperties);
13234 }
13235
13236 if (isset($properties['DIRECTION']) && $properties['DIRECTION']) {
13237 $this->cssManager->CSS['BODY']['DIRECTION'] = $properties['DIRECTION'];
13238 }
13239 if (!isset($this->cssManager->CSS['BODY']['DIRECTION'])) {
13240 $this->cssManager->CSS['BODY']['DIRECTION'] = $this->directionality;
13241 } else {
13242 $this->SetDirectionality($this->cssManager->CSS['BODY']['DIRECTION']);
13243 }
13244
13245 $this->setCSS($properties, '', 'BODY');
13246
13247 $this->blk[0]['InlineProperties'] = $this->saveInlineProperties();
13248
13249 if ($mode === HTMLParserMode::HEADER_CSS) {
13250 return '';
13251 }
13252 if (!isset($this->cssManager->CSS['BODY'])) {
13253 $this->cssManager->CSS['BODY'] = [];
13254 }
13255
13256 /* -- BACKGROUNDS -- */
13257 if (isset($properties['BACKGROUND-GRADIENT'])) {
13258 $this->bodyBackgroundGradient = $properties['BACKGROUND-GRADIENT'];
13259 }
13260
13261 if (isset($properties['BACKGROUND-IMAGE']) && $properties['BACKGROUND-IMAGE']) {
13262 $ret = $this->SetBackground($properties, $this->pgwidth);
13263 if ($ret) {
13264 $this->bodyBackgroundImage = $ret;
13265 }
13266 }
13267 /* -- END BACKGROUNDS -- */
13268
13269 /* -- CSS-PAGE -- */
13270 // If page-box is set
13271 if ($this->state == 0 && ((isset($this->cssManager->CSS['@PAGE']) && $this->cssManager->CSS['@PAGE']) || (isset($this->cssManager->CSS['@PAGE>>PSEUDO>>FIRST']) && $this->cssManager->CSS['@PAGE>>PSEUDO>>FIRST']))) { // mPDF 5.7.3
13272 $this->page_box['current'] = '';
13273 $this->page_box['using'] = true;
13274 list($pborientation, $pbmgl, $pbmgr, $pbmgt, $pbmgb, $pbmgh, $pbmgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS('', false, 'O');
13275 $this->DefOrientation = $this->CurOrientation = $pborientation;
13276 $this->orig_lMargin = $this->DeflMargin = $pbmgl;
13277 $this->orig_rMargin = $this->DefrMargin = $pbmgr;
13278 $this->orig_tMargin = $this->tMargin = $pbmgt;
13279 $this->orig_bMargin = $this->bMargin = $pbmgb;
13280 $this->orig_hMargin = $this->margin_header = $pbmgh;
13281 $this->orig_fMargin = $this->margin_footer = $pbmgf;
13282 list($pborientation, $pbmgl, $pbmgr, $pbmgt, $pbmgb, $pbmgh, $pbmgf, $hname, $fname, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat) = $this->SetPagedMediaCSS('', true, 'O'); // first page
13283 $this->show_marks = $marks;
13284 if ($hname) {
13285 $this->firstPageBoxHeader = $hname;
13286 }
13287 if ($fname) {
13288 $this->firstPageBoxFooter = $fname;
13289 }
13290 }
13291 /* -- END CSS-PAGE -- */
13292
13293 $parseonly = false;
13294 $this->bufferoutput = false;
13296 $parseonly = true;
13297 // Close any open block tags
13298 $arr = [];
13299 $ai = 0;
13300 for ($b = $this->blklvl; $b > 0; $b--) {
13301 $this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
13302 }
13303 // Output any text left in buffer
13304 if (count($this->textbuffer)) {
13305 $this->printbuffer($this->textbuffer);
13306 }
13307 $this->textbuffer = [];
13308 } elseif ($mode === HTMLParserMode::HTML_HEADER_BUFFER) {
13309 // Close any open block tags
13310 $arr = [];
13311 $ai = 0;
13312 for ($b = $this->blklvl; $b > 0; $b--) {
13313 $this->tag->CloseTag($this->blk[$b]['tag'], $arr, $ai);
13314 }
13315 // Output any text left in buffer
13316 if (count($this->textbuffer)) {
13317 $this->printbuffer($this->textbuffer);
13318 }
13319 $this->bufferoutput = true;
13320 $this->textbuffer = [];
13321 $this->headerbuffer = '';
13322 $properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', '');
13323 $this->setCSS($properties, '', 'BODY');
13324 }
13325
13326 mb_internal_encoding('UTF-8');
13327
13328 $html = $this->AdjustHTML($html, $this->tabSpaces); // Try to make HTML look more like XHTML
13329
13330 if ($this->autoScriptToLang) {
13331 $html = $this->markScriptToLang($html);
13332 }
13333
13334 preg_match_all('/<htmlpageheader([^>]*)>(.*?)<\/htmlpageheader>/si', $html, $h);
13335 for ($i = 0; $i < count($h[1]); $i++) {
13336 if (preg_match('/name=[\'|\"](.*?)[\'|\"]/', $h[1][$i], $n)) {
13337 $this->pageHTMLheaders[$n[1]]['html'] = $h[2][$i];
13338 $this->pageHTMLheaders[$n[1]]['h'] = $this->_getHtmlHeight($h[2][$i]);
13339 }
13340 }
13341 preg_match_all('/<htmlpagefooter([^>]*)>(.*?)<\/htmlpagefooter>/si', $html, $f);
13342 for ($i = 0; $i < count($f[1]); $i++) {
13343 if (preg_match('/name=[\'|\"](.*?)[\'|\"]/', $f[1][$i], $n)) {
13344 $this->pageHTMLfooters[$n[1]]['html'] = $f[2][$i];
13345 $this->pageHTMLfooters[$n[1]]['h'] = $this->_getHtmlHeight($f[2][$i]);
13346 }
13347 }
13348
13349 $html = preg_replace('/<htmlpageheader.*?<\/htmlpageheader>/si', '', $html);
13350 $html = preg_replace('/<htmlpagefooter.*?<\/htmlpagefooter>/si', '', $html);
13351
13352 if ($this->state == 0 && ($mode === HTMLParserMode::DEFAULT_MODE || $mode === HTMLParserMode::HTML_BODY)) {
13353 $this->AddPage($this->CurOrientation);
13354 }
13355
13356
13357 if (isset($hname) && preg_match('/^html_(.*)$/i', $hname, $n)) {
13358 $this->SetHTMLHeader($this->pageHTMLheaders[$n[1]], 'O', true);
13359 }
13360 if (isset($fname) && preg_match('/^html_(.*)$/i', $fname, $n)) {
13361 $this->SetHTMLFooter($this->pageHTMLfooters[$n[1]], 'O');
13362 }
13363
13364
13365
13366 $html = str_replace('<?', '< ', $html); // Fix '<?XML' bug from HTML code generated by MS Word
13367
13368 $this->checkSIP = false;
13369 $this->checkSMP = false;
13370 $this->checkCJK = false;
13371 if ($this->onlyCoreFonts) {
13372 $html = $this->SubstituteChars($html);
13373 } else {
13374 if (preg_match("/([" . $this->pregRTLchars . "])/u", $html)) {
13375 $this->biDirectional = true;
13376 } // *OTL*
13377 if (preg_match("/([\x{20000}-\x{2FFFF}])/u", $html)) {
13378 $this->checkSIP = true;
13379 }
13380 if (preg_match("/([\x{10000}-\x{1FFFF}])/u", $html)) {
13381 $this->checkSMP = true;
13382 }
13383 /* -- CJK-FONTS -- */
13384 if (preg_match("/([" . $this->pregCJKchars . "])/u", $html)) {
13385 $this->checkCJK = true;
13386 }
13387 /* -- END CJK-FONTS -- */
13388 }
13389
13390 // Don't allow non-breaking spaces that are converted to substituted chars or will break anyway and mess up table width calc.
13391 $html = str_replace('<tta>160</tta>', chr(32), $html);
13392 $html = str_replace('</tta><tta>', '|', $html);
13393 $html = str_replace('</tts><tts>', '|', $html);
13394 $html = str_replace('</ttz><ttz>', '|', $html);
13395
13396 // Add new supported tags in the DisableTags function
13397 $html = strip_tags($html, $this->enabledtags); // remove all unsupported tags, but the ones inside the 'enabledtags' string
13398 // Explode the string in order to parse the HTML code
13399 $a = preg_split('/<(.*?)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
13400 // ? more accurate regexp that allows e.g. <a name="Silly <name>">
13401 // if changing - also change in fn.SubstituteChars()
13402 // $a = preg_split ('/<((?:[^<>]+(?:"[^"]*"|\'[^\']*\')?)+)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
13403
13404 if ($this->mb_enc) {
13405 mb_internal_encoding($this->mb_enc);
13406 }
13407 $pbc = 0;
13408 $this->subPos = -1;
13409 $cnt = count($a);
13410 for ($i = 0; $i < $cnt; $i++) {
13411 $e = $a[$i];
13412 if ($i % 2 == 0) {
13413 // TEXT
13414 if ($this->blk[$this->blklvl]['hide']) {
13415 continue;
13416 }
13417 if ($this->inlineDisplayOff) {
13418 continue;
13419 }
13420 if ($this->inMeter) {
13421 continue;
13422 }
13423
13424 if ($this->inFixedPosBlock) {
13425 $this->fixedPosBlock .= $e;
13426 continue;
13427 } // *CSS-POSITION*
13428 if (strlen($e) == 0) {
13429 continue;
13430 }
13431
13432 if ($this->ignorefollowingspaces && !$this->ispre) {
13433 if (strlen(ltrim($e)) == 0) {
13434 continue;
13435 }
13436 if ($this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats' && substr($e, 0, 1) == ' ') {
13437 $this->ignorefollowingspaces = false;
13438 $e = ltrim($e);
13439 }
13440 }
13441
13442 $this->OTLdata = null; // mPDF 5.7.1
13443
13444 $e = UtfString::strcode2utf($e);
13445 $e = $this->lesser_entity_decode($e);
13446
13447 if ($this->usingCoreFont) {
13448 // If core font is selected in document which is not onlyCoreFonts - substitute with non-core font
13449 if ($this->useSubstitutions && !$this->onlyCoreFonts && $this->subPos < $i && !$this->specialcontent) {
13450 $cnt += $this->SubstituteCharsNonCore($a, $i, $e);
13451 }
13452 // CONVERT ENCODING
13453 $e = mb_convert_encoding($e, $this->mb_enc, 'UTF-8');
13454 if ($this->textvar & TextVars::FT_UPPERCASE) {
13455 $e = mb_strtoupper($e, $this->mb_enc);
13456 } // mPDF 5.7.1
13457 elseif ($this->textvar & TextVars::FT_LOWERCASE) {
13458 $e = mb_strtolower($e, $this->mb_enc);
13459 } // mPDF 5.7.1
13460 elseif ($this->textvar & TextVars::FT_CAPITALIZE) {
13461 $e = mb_convert_case($e, MB_CASE_TITLE, "UTF-8");
13462 } // mPDF 5.7.1
13463 } else {
13464 if ($this->checkSIP && $this->CurrentFont['sipext'] && $this->subPos < $i && (!$this->specialcontent || !$this->useActiveForms)) {
13465 $cnt += $this->SubstituteCharsSIP($a, $i, $e);
13466 }
13467
13468 if ($this->useSubstitutions && !$this->onlyCoreFonts && $this->CurrentFont['type'] != 'Type0' && $this->subPos < $i && (!$this->specialcontent || !$this->useActiveForms)) {
13469 $cnt += $this->SubstituteCharsMB($a, $i, $e);
13470 }
13471
13472 if ($this->textvar & TextVars::FT_UPPERCASE) {
13473 $e = mb_strtoupper($e, $this->mb_enc);
13474 } elseif ($this->textvar & TextVars::FT_LOWERCASE) {
13475 $e = mb_strtolower($e, $this->mb_enc);
13476 } elseif ($this->textvar & TextVars::FT_CAPITALIZE) {
13477 $e = mb_convert_case($e, MB_CASE_TITLE, "UTF-8");
13478 }
13479
13480 /* -- OTL -- */
13481 // Use OTL OpenType Table Layout - GSUB & GPOS
13482 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL'] && (!$this->specialcontent || !$this->useActiveForms)) {
13483 if (!$this->otl) {
13484 $this->otl = new Otl($this, $this->fontCache);
13485 }
13486 $e = $this->otl->applyOTL($e, $this->CurrentFont['useOTL']);
13487 $this->OTLdata = $this->otl->OTLdata;
13488 $this->otl->removeChar($e, $this->OTLdata, "\xef\xbb\xbf"); // Remove ZWNBSP (also Byte order mark FEFF)
13489 } /* -- END OTL -- */
13490 else {
13491 // removes U+200E/U+200F LTR and RTL mark and U+200C/U+200D Zero-width Joiner and Non-joiner
13492 $e = preg_replace("/[\xe2\x80\x8c\xe2\x80\x8d\xe2\x80\x8e\xe2\x80\x8f]/u", '', $e);
13493 $e = preg_replace("/[\xef\xbb\xbf]/u", '', $e); // Remove ZWNBSP (also Byte order mark FEFF)
13494 }
13495 }
13496
13497 if (($this->tts) || ($this->ttz) || ($this->tta)) {
13498 $es = explode('|', $e);
13499 $e = '';
13500 foreach ($es as $val) {
13501 $e .= chr($val);
13502 }
13503 }
13504
13505 // FORM ELEMENTS
13506 if ($this->specialcontent) {
13507 /* -- FORMS -- */
13508 // SELECT tag (form element)
13509 if ($this->specialcontent == "type=select") {
13510 $e = ltrim($e);
13511 if (!empty($this->OTLdata)) {
13512 $this->otl->trimOTLdata($this->OTLdata, true, false);
13513 } // *OTL*
13514 $stringwidth = $this->GetStringWidth($e);
13515 if (!isset($this->selectoption['MAXWIDTH']) || $stringwidth > $this->selectoption['MAXWIDTH']) {
13516 $this->selectoption['MAXWIDTH'] = $stringwidth;
13517 }
13518 if (!isset($this->selectoption['SELECTED']) || $this->selectoption['SELECTED'] == '') {
13519 $this->selectoption['SELECTED'] = $e;
13520 if (!empty($this->OTLdata)) {
13521 $this->selectoption['SELECTED-OTLDATA'] = $this->OTLdata;
13522 } // *OTL*
13523 }
13524 // Active Forms
13525 if (isset($this->selectoption['ACTIVE']) && $this->selectoption['ACTIVE']) {
13526 $this->selectoption['ITEMS'][] = ['exportValue' => $this->selectoption['currentVAL'], 'content' => $e, 'selected' => $this->selectoption['currentSEL']];
13527 }
13528 $this->OTLdata = [];
13529 } // TEXTAREA
13530 else {
13531 $objattr = unserialize($this->specialcontent);
13532 $objattr['text'] = $e;
13533 $objattr['OTLdata'] = $this->OTLdata;
13534 $this->OTLdata = [];
13535 $te = "\xbb\xa4\xactype=textarea,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
13536 if ($this->tdbegin) {
13537 $this->_saveCellTextBuffer($te, $this->HREF);
13538 } else {
13539 $this->_saveTextBuffer($te, $this->HREF);
13540 }
13541 }
13542 /* -- END FORMS -- */
13543 } // TABLE
13544 elseif ($this->tableLevel) {
13545 /* -- TABLES -- */
13546 if ($this->tdbegin) {
13547 if (($this->ignorefollowingspaces) && !$this->ispre) {
13548 $e = ltrim($e);
13549 if (!empty($this->OTLdata)) {
13550 $this->otl->trimOTLdata($this->OTLdata, true, false);
13551 } // *OTL*
13552 }
13553 if ($e || $e === '0') {
13554 if ($this->blockjustfinished && $this->cell[$this->row][$this->col]['s'] > 0) {
13555 $this->_saveCellTextBuffer("\n");
13556 if (!isset($this->cell[$this->row][$this->col]['maxs'])) {
13557 $this->cell[$this->row][$this->col]['maxs'] = $this->cell[$this->row][$this->col]['s'];
13558 } elseif ($this->cell[$this->row][$this->col]['maxs'] < $this->cell[$this->row][$this->col]['s']) {
13559 $this->cell[$this->row][$this->col]['maxs'] = $this->cell[$this->row][$this->col]['s'];
13560 }
13561 $this->cell[$this->row][$this->col]['s'] = 0; // reset
13562 }
13563 $this->blockjustfinished = false;
13564
13565 if (!isset($this->cell[$this->row][$this->col]['R']) || !$this->cell[$this->row][$this->col]['R']) {
13566 if (isset($this->cell[$this->row][$this->col]['s'])) {
13567 $this->cell[$this->row][$this->col]['s'] += $this->GetStringWidth($e, false, $this->OTLdata, $this->textvar);
13568 } else {
13569 $this->cell[$this->row][$this->col]['s'] = $this->GetStringWidth($e, false, $this->OTLdata, $this->textvar);
13570 }
13571 if (!empty($this->spanborddet)) {
13572 $this->cell[$this->row][$this->col]['s'] += (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0) + (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
13573 }
13574 }
13575
13576 $this->_saveCellTextBuffer($e, $this->HREF);
13577
13578 if (substr($this->cell[$this->row][$this->col]['a'], 0, 1) == 'D') {
13579
13580 $dp = $this->decimal_align[substr($this->cell[$this->row][$this->col]['a'], 0, 2)];
13581 $s = preg_split('/' . preg_quote($dp, '/') . '/', $e, 2); // ? needs to be /u if not core
13582 $s0 = $this->GetStringWidth($s[0], false);
13583
13584 if (isset($s[1]) && $s[1]) {
13585 $s1 = $this->GetStringWidth(($s[1] . $dp), false);
13586 } else {
13587 $s1 = 0;
13588 }
13589
13590 if (!isset($this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0'])) {
13591 if ($this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'] === false) {
13592 $this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'] = [];
13593 }
13594 $this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0'] = $s0;
13595 } else {
13596 $this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0'] = max($s0, $this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs0']);
13597 }
13598
13599 if (!isset($this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1'])) {
13600 $this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1'] = $s1;
13601 } else {
13602 $this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1'] = max($s1, $this->table[$this->tableLevel][$this->tbctr[$this->tableLevel]]['decimal_align'][$this->col]['maxs1']);
13603 }
13604 }
13605
13606 $this->nestedtablejustfinished = false;
13607 $this->linebreakjustfinished = false;
13608 }
13609 }
13610 /* -- END TABLES -- */
13611 } // ALL ELSE
13612 else {
13613 if ($this->ignorefollowingspaces && !$this->ispre) {
13614 $e = ltrim($e);
13615 if (!empty($this->OTLdata)) {
13616 $this->otl->trimOTLdata($this->OTLdata, true, false);
13617 } // *OTL*
13618 }
13619 if ($e || $e === '0') {
13620 $this->_saveTextBuffer($e, $this->HREF);
13621 }
13622 }
13623 if ($e || $e === '0') {
13624 $this->ignorefollowingspaces = false; // mPDF 6
13625 }
13626 if (substr($e, -1, 1) == ' ' && !$this->ispre && $this->FontFamily != 'csymbol' && $this->FontFamily != 'czapfdingbats') {
13627 $this->ignorefollowingspaces = true;
13628 }
13629 } else { // TAG **
13630 if (isset($e[0]) && $e[0] == '/') {
13631 $endtag = trim(strtoupper(substr($e, 1)));
13632
13633 /* -- CSS-POSITION -- */
13634 // mPDF 6
13635 if ($this->inFixedPosBlock) {
13636 if (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags)) {
13637 $this->fixedPosBlockDepth--;
13638 }
13639 if ($this->fixedPosBlockDepth == 0) {
13640 $this->fixedPosBlockSave[] = [$this->fixedPosBlock, $this->fixedPosBlockBBox, $this->page];
13641 $this->fixedPosBlock = '';
13642 $this->inFixedPosBlock = false;
13643 continue;
13644 }
13645 $this->fixedPosBlock .= '<' . $e . '>';
13646 continue;
13647 }
13648 /* -- END CSS-POSITION -- */
13649
13650 // mPDF 6
13651 // Correct for tags where HTML5 specifies optional end tags (see also OpenTag() )
13652 if ($this->allow_html_optional_endtags && !$parseonly) {
13653 if (isset($this->blk[$this->blklvl]['tag'])) {
13654 $closed = false;
13655 // li end tag may be omitted if there is no more content in the parent element
13656 if (!$closed && $this->blk[$this->blklvl]['tag'] == 'LI' && $endtag != 'LI' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
13657 $this->tag->CloseTag('LI', $a, $i);
13658 $closed = true;
13659 }
13660 // dd end tag may be omitted if there is no more content in the parent element
13661 if (!$closed && $this->blk[$this->blklvl]['tag'] == 'DD' && $endtag != 'DD' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
13662 $this->tag->CloseTag('DD', $a, $i);
13663 $closed = true;
13664 }
13665 // p end tag may be omitted if there is no more content in the parent element and the parent element is not an A element [??????]
13666 if (!$closed && $this->blk[$this->blklvl]['tag'] == 'P' && $endtag != 'P' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
13667 $this->tag->CloseTag('P', $a, $i);
13668 $closed = true;
13669 }
13670 // option end tag may be omitted if there is no more content in the parent element
13671 if (!$closed && $this->blk[$this->blklvl]['tag'] == 'OPTION' && $endtag != 'OPTION' && (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags))) {
13672 $this->tag->CloseTag('OPTION', $a, $i);
13673 $closed = true;
13674 }
13675 }
13676 /* -- TABLES -- */
13677 // Check for Table tags where HTML specifies optional end tags,
13678 if ($endtag == 'TABLE') {
13679 if ($this->lastoptionaltag == 'THEAD' || $this->lastoptionaltag == 'TBODY' || $this->lastoptionaltag == 'TFOOT') {
13680 $this->tag->CloseTag($this->lastoptionaltag, $a, $i);
13681 }
13682 if ($this->lastoptionaltag == 'TR') {
13683 $this->tag->CloseTag('TR', $a, $i);
13684 }
13685 if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
13686 $this->tag->CloseTag($this->lastoptionaltag, $a, $i);
13687 $this->tag->CloseTag('TR', $a, $i);
13688 }
13689 }
13690 if ($endtag == 'THEAD' || $endtag == 'TBODY' || $endtag == 'TFOOT') {
13691 if ($this->lastoptionaltag == 'TR') {
13692 $this->tag->CloseTag('TR', $a, $i);
13693 }
13694 if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
13695 $this->tag->CloseTag($this->lastoptionaltag, $a, $i);
13696 $this->tag->CloseTag('TR', $a, $i);
13697 }
13698 }
13699 if ($endtag == 'TR') {
13700 if ($this->lastoptionaltag == 'TD' || $this->lastoptionaltag == 'TH') {
13701 $this->tag->CloseTag($this->lastoptionaltag, $a, $i);
13702 }
13703 }
13704 /* -- END TABLES -- */
13705 }
13706
13707
13708 // mPDF 6
13709 if ($this->blk[$this->blklvl]['hide']) {
13710 if (in_array($endtag, $this->outerblocktags) || in_array($endtag, $this->innerblocktags)) {
13711 unset($this->blk[$this->blklvl]);
13712 $this->blklvl--;
13713 }
13714 continue;
13715 }
13716
13717 // mPDF 6
13718 $this->tag->CloseTag($endtag, $a, $i); // mPDF 6
13719 } else { // OPENING TAG
13720 if ($this->blk[$this->blklvl]['hide']) {
13721 if (strpos($e, ' ')) {
13722 $te = strtoupper(substr($e, 0, strpos($e, ' ')));
13723 } else {
13724 $te = strtoupper($e);
13725 }
13726 // mPDF 6
13727 if ($te == 'THEAD' || $te == 'TBODY' || $te == 'TFOOT' || $te == 'TR' || $te == 'TD' || $te == 'TH') {
13728 $this->lastoptionaltag = $te;
13729 }
13730 if (in_array($te, $this->outerblocktags) || in_array($te, $this->innerblocktags)) {
13731 $this->blklvl++;
13732 $this->blk[$this->blklvl]['hide'] = true;
13733 $this->blk[$this->blklvl]['tag'] = $te; // mPDF 6
13734 }
13735 continue;
13736 }
13737
13738 /* -- CSS-POSITION -- */
13739 if ($this->inFixedPosBlock) {
13740 if (strpos($e, ' ')) {
13741 $te = strtoupper(substr($e, 0, strpos($e, ' ')));
13742 } else {
13743 $te = strtoupper($e);
13744 }
13745 $this->fixedPosBlock .= '<' . $e . '>';
13746 if (in_array($te, $this->outerblocktags) || in_array($te, $this->innerblocktags)) {
13747 $this->fixedPosBlockDepth++;
13748 }
13749 continue;
13750 }
13751 /* -- END CSS-POSITION -- */
13752 $regexp = '|=\'(.*?)\'|s'; // eliminate single quotes, if any
13753 $e = preg_replace($regexp, "=\"\$1\"", $e);
13754 // changes anykey=anyvalue to anykey="anyvalue" (only do this inside [some] tags)
13755 if (substr($e, 0, 10) != 'pageheader' && substr($e, 0, 10) != 'pagefooter' && substr($e, 0, 12) != 'tocpagebreak' && substr($e, 0, 10) != 'indexentry' && substr($e, 0, 8) != 'tocentry') { // mPDF 6 (ZZZ99H)
13756 $regexp = '| (\\w+?)=([^\\s>"]+)|si';
13757 $e = preg_replace($regexp, " \$1=\"\$2\"", $e);
13758 }
13759
13760 $e = preg_replace('/ (\\S+?)\s*=\s*"/i', " \\1=\"", $e);
13761
13762 // Fix path values, if needed
13763 $orig_srcpath = '';
13764 if ((stristr($e, "href=") !== false) or ( stristr($e, "src=") !== false)) {
13765 $regexp = '/ (href|src)\s*=\s*"(.*?)"/i';
13766 preg_match($regexp, $e, $auxiliararray);
13767 if (isset($auxiliararray[2])) {
13768 $path = $auxiliararray[2];
13769 } else {
13770 $path = '';
13771 }
13772 if (trim($path) != '' && !(stristr($e, "src=") !== false && substr($path, 0, 4) == 'var:') && substr($path, 0, 1) != '@') {
13773 $path = htmlspecialchars_decode($path); // mPDF 5.7.4 URLs
13774 $orig_srcpath = $path;
13775 $this->GetFullPath($path);
13776 $regexp = '/ (href|src)="(.*?)"/i';
13777 $e = preg_replace($regexp, ' \\1="' . $path . '"', $e);
13778 }
13779 }//END of Fix path values
13780 // Extract attributes
13781 $contents = [];
13782 $contents1 = [];
13783 $contents2 = [];
13784 // Changed to allow style="background: url('bg.jpg')"
13785 // Changed to improve performance; maximum length of \S (attribute) = 16
13786 // Increase allowed attribute name to 32 - cutting off "toc-even-header-name" etc.
13787 preg_match_all('/\\S{1,32}=["][^"]*["]/', $e, $contents1);
13788 preg_match_all('/\\S{1,32}=[\'][^\']*[\']/i', $e, $contents2);
13789
13790 $contents = array_merge($contents1, $contents2);
13791 preg_match('/\\S+/', $e, $a2);
13792 $tag = (isset($a2[0]) ? strtoupper($a2[0]) : '');
13793 $attr = [];
13794 if ($orig_srcpath) {
13795 $attr['ORIG_SRC'] = $orig_srcpath;
13796 }
13797 if (!empty($contents)) {
13798 foreach ($contents[0] as $v) {
13799 // Changed to allow style="background: url('bg.jpg')"
13800 if (preg_match('/^([^=]*)=["]?([^"]*)["]?$/', $v, $a3) || preg_match('/^([^=]*)=[\']?([^\']*)[\']?$/', $v, $a3)) {
13801 if (strtoupper($a3[1]) == 'ID' || strtoupper($a3[1]) == 'CLASS') { // 4.2.013 Omits STYLE
13802 $attr[strtoupper($a3[1])] = trim(strtoupper($a3[2]));
13803 } // includes header-style-right etc. used for <pageheader>
13804 elseif (preg_match('/^(HEADER|FOOTER)-STYLE/i', $a3[1])) {
13805 $attr[strtoupper($a3[1])] = trim(strtoupper($a3[2]));
13806 } else {
13807 $attr[strtoupper($a3[1])] = trim($a3[2]);
13808 }
13809 }
13810 }
13811 }
13812 $this->tag->OpenTag($tag, $attr, $a, $i); // mPDF 6
13813 /* -- CSS-POSITION -- */
13814 if ($this->inFixedPosBlock) {
13815 $this->fixedPosBlockBBox = [$tag, $attr, $this->x, $this->y];
13816 $this->fixedPosBlock = '';
13817 $this->fixedPosBlockDepth = 1;
13818 }
13819 /* -- END CSS-POSITION -- */
13820 if (preg_match('/\/$/', $e)) {
13821 $this->tag->CloseTag($tag, $a, $i);
13822 }
13823 }
13824 } // end TAG
13825 } // end of foreach($a as $i=>$e)
13826
13827 if ($close) {
13828 // Close any open block tags
13829 for ($b = $this->blklvl; $b > 0; $b--) {
13830 $this->tag->CloseTag($this->blk[$b]['tag'], $a, $i);
13831 }
13832
13833 // Output any text left in buffer
13834 if (count($this->textbuffer) && !$parseonly) {
13835 $this->printbuffer($this->textbuffer);
13836 }
13837 if (!$parseonly) {
13838 $this->textbuffer = [];
13839 }
13840
13841 /* -- CSS-FLOAT -- */
13842 // If ended with a float, need to move to end page
13843 $currpos = $this->page * 1000 + $this->y;
13844 if (isset($this->blk[$this->blklvl]['float_endpos']) && $this->blk[$this->blklvl]['float_endpos'] > $currpos) {
13845 $old_page = $this->page;
13846 $new_page = intval($this->blk[$this->blklvl]['float_endpos'] / 1000);
13847 if ($old_page != $new_page) {
13848 $s = $this->PrintPageBackgrounds();
13849 // Writes after the marker so not overwritten later by page background etc.
13850 $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
13851 $this->pageBackgrounds = [];
13852 $this->page = $new_page;
13853 $this->ResetMargins();
13854 $this->Reset();
13855 $this->pageoutput[$this->page] = [];
13856 }
13857 $this->y = (round($this->blk[$this->blklvl]['float_endpos'] * 1000) % 1000000) / 1000; // mod changes operands to integers before processing
13858 }
13859 /* -- END CSS-FLOAT -- */
13860
13861 /* -- CSS-IMAGE-FLOAT -- */
13862 $this->printfloatbuffer();
13863 /* -- END CSS-IMAGE-FLOAT -- */
13864
13865 // Create Internal Links, if needed
13866 if (!empty($this->internallink)) {
13867
13868 foreach ($this->internallink as $k => $v) {
13869
13870 if (strpos($k, "#") !== false) {
13871 continue;
13872 }
13873
13874 if (!is_array($v)) {
13875 continue;
13876 }
13877
13878 $ypos = $v['Y'];
13879 $pagenum = $v['PAGE'];
13880 $sharp = "#";
13881
13882 while (array_key_exists($sharp . $k, $this->internallink)) {
13883 $internallink = $this->internallink[$sharp . $k];
13884 $this->SetLink($internallink, $ypos, $pagenum);
13885 $sharp .= "#";
13886 }
13887 }
13888 }
13889
13890 $this->bufferoutput = false;
13891
13892 /* -- CSS-POSITION -- */
13893 if (count($this->fixedPosBlockSave)) {
13894 foreach ($this->fixedPosBlockSave as $fpbs) {
13895 $old_page = $this->page;
13896 $this->page = $fpbs[2];
13897 $this->WriteFixedPosHTML($fpbs[0], 0, 0, 100, 100, 'auto', $fpbs[1]); // 0,0,10,10 are overwritten by bbox
13898 $this->page = $old_page;
13899 }
13900 $this->fixedPosBlockSave = [];
13901 }
13902 /* -- END CSS-POSITION -- */
13903 }
13904 }
13905
13906 /* -- CSS-POSITION -- */
13907
13908 function WriteFixedPosHTML($html, $x, $y, $w, $h, $overflow = 'visible', $bounding = [])
13909 {
13910 // $overflow can be 'hidden', 'visible' or 'auto' - 'auto' causes autofit to size
13911 // Annotations disabled - enabled in mPDF 5.0
13912 // Links do work
13913 // Will always go on current page (or start Page 1 if required)
13914 // Probably INCOMPATIBLE WITH keep with table, columns etc.
13915 // Called externally or interally via <div style="position: [fixed|absolute]">
13916 // When used internally, $x $y $w $h and $overflow are all overridden by $bounding
13917
13918 $overflow = strtolower($overflow);
13919 if ($this->state == 0) {
13920 $this->AddPage($this->CurOrientation);
13921 }
13922 $save_y = $this->y;
13923 $save_x = $this->x;
13924 $this->fullImageHeight = $this->h;
13925 $save_cols = false;
13926 /* -- COLUMNS -- */
13927 if ($this->ColActive) {
13928 $save_cols = true;
13929 $save_nbcol = $this->NbCol; // other values of gap and vAlign will not change by setting Columns off
13930 $this->SetColumns(0);
13931 }
13932 /* -- END COLUMNS -- */
13933 $save_annots = $this->title2annots; // *ANNOTATIONS*
13934 $this->writingHTMLheader = true; // a FIX to stop pagebreaks etc.
13935 $this->writingHTMLfooter = true;
13936 $this->InFooter = true; // suppresses autopagebreaks
13937 $save_bgs = $this->pageBackgrounds;
13938 $checkinnerhtml = preg_replace('/\s/', '', $html);
13939 $rotate = 0;
13940
13941 if ($w > $this->w) {
13942 $x = 0;
13943 $w = $this->w;
13944 }
13945 if ($h > $this->h) {
13946 $y = 0;
13947 $h = $this->h;
13948 }
13949 if ($x > $this->w) {
13950 $x = $this->w - $w;
13951 }
13952 if ($y > $this->h) {
13953 $y = $this->h - $h;
13954 }
13955
13956 if (!empty($bounding)) {
13957 // $cont_ containing block = full physical page (position: absolute) or page inside margins (position: fixed)
13958 // $bbox_ Bounding box is the <div> which is positioned absolutely/fixed
13959 // top/left/right/bottom/width/height/background*/border*/padding*/margin* are taken from bounding
13960 // font*[family/size/style/weight]/line-height/text*[align/decoration/transform/indent]/color are transferred to $inner
13961 // as an enclosing <div> (after having checked ID/CLASS)
13962 // $x, $y, $w, $h are inside of $bbox_ = containing box for $inner_
13963 // $inner_ InnerHTML is the contents of that block to be output
13964 $tag = $bounding[0];
13965 $attr = $bounding[1];
13966 $orig_x0 = $bounding[2];
13967 $orig_y0 = $bounding[3];
13968
13969 // As in WriteHTML() initialising
13970 $this->blklvl = 0;
13971 $this->lastblocklevelchange = 0;
13972 $this->blk = [];
13973 $this->initialiseBlock($this->blk[0]);
13974
13975 $this->blk[0]['width'] = & $this->pgwidth;
13976 $this->blk[0]['inner_width'] = & $this->pgwidth;
13977
13978 $this->blk[0]['blockContext'] = $this->blockContext;
13979
13980 $properties = $this->cssManager->MergeCSS('BLOCK', 'BODY', '');
13981 $this->setCSS($properties, '', 'BODY');
13982 $this->blklvl = 1;
13983 $this->initialiseBlock($this->blk[1]);
13984 $this->blk[1]['tag'] = $tag;
13985 $this->blk[1]['attr'] = $attr;
13986 $this->Reset();
13987 $p = $this->cssManager->MergeCSS('BLOCK', $tag, $attr);
13988 if (isset($p['ROTATE']) && ($p['ROTATE'] == 90 || $p['ROTATE'] == -90 || $p['ROTATE'] == 180)) {
13989 $rotate = $p['ROTATE'];
13990 } // mPDF 6
13991 if (isset($p['OVERFLOW'])) {
13992 $overflow = strtolower($p['OVERFLOW']);
13993 }
13994 if (strtolower($p['POSITION']) == 'fixed') {
13995 $cont_w = $this->pgwidth; // $this->blk[0]['inner_width'];
13996 $cont_h = $this->h - $this->tMargin - $this->bMargin;
13997 $cont_x = $this->lMargin;
13998 $cont_y = $this->tMargin;
13999 } else {
14000 $cont_w = $this->w; // ABSOLUTE;
14001 $cont_h = $this->h;
14002 $cont_x = 0;
14003 $cont_y = 0;
14004 }
14005
14006 // Pass on in-line properties to the innerhtml
14007 $css = '';
14008 if (isset($p['TEXT-ALIGN'])) {
14009 $css .= 'text-align: ' . strtolower($p['TEXT-ALIGN']) . '; ';
14010 }
14011 if (isset($p['TEXT-TRANSFORM'])) {
14012 $css .= 'text-transform: ' . strtolower($p['TEXT-TRANSFORM']) . '; ';
14013 }
14014 if (isset($p['TEXT-INDENT'])) {
14015 $css .= 'text-indent: ' . strtolower($p['TEXT-INDENT']) . '; ';
14016 }
14017 if (isset($p['TEXT-DECORATION'])) {
14018 $css .= 'text-decoration: ' . strtolower($p['TEXT-DECORATION']) . '; ';
14019 }
14020 if (isset($p['FONT-FAMILY'])) {
14021 $css .= 'font-family: ' . strtolower($p['FONT-FAMILY']) . '; ';
14022 }
14023 if (isset($p['FONT-STYLE'])) {
14024 $css .= 'font-style: ' . strtolower($p['FONT-STYLE']) . '; ';
14025 }
14026 if (isset($p['FONT-WEIGHT'])) {
14027 $css .= 'font-weight: ' . strtolower($p['FONT-WEIGHT']) . '; ';
14028 }
14029 if (isset($p['FONT-SIZE'])) {
14030 $css .= 'font-size: ' . strtolower($p['FONT-SIZE']) . '; ';
14031 }
14032 if (isset($p['LINE-HEIGHT'])) {
14033 $css .= 'line-height: ' . strtolower($p['LINE-HEIGHT']) . '; ';
14034 }
14035 if (isset($p['TEXT-SHADOW'])) {
14036 $css .= 'text-shadow: ' . strtolower($p['TEXT-SHADOW']) . '; ';
14037 }
14038 if (isset($p['LETTER-SPACING'])) {
14039 $css .= 'letter-spacing: ' . strtolower($p['LETTER-SPACING']) . '; ';
14040 }
14041 // mPDF 6
14042 if (isset($p['FONT-VARIANT-POSITION'])) {
14043 $css .= 'font-variant-position: ' . strtolower($p['FONT-VARIANT-POSITION']) . '; ';
14044 }
14045 if (isset($p['FONT-VARIANT-CAPS'])) {
14046 $css .= 'font-variant-caps: ' . strtolower($p['FONT-VARIANT-CAPS']) . '; ';
14047 }
14048 if (isset($p['FONT-VARIANT-LIGATURES'])) {
14049 $css .= 'font-variant-ligatures: ' . strtolower($p['FONT-VARIANT-LIGATURES']) . '; ';
14050 }
14051 if (isset($p['FONT-VARIANT-NUMERIC'])) {
14052 $css .= 'font-variant-numeric: ' . strtolower($p['FONT-VARIANT-NUMERIC']) . '; ';
14053 }
14054 if (isset($p['FONT-VARIANT-ALTERNATES'])) {
14055 $css .= 'font-variant-alternates: ' . strtolower($p['FONT-VARIANT-ALTERNATES']) . '; ';
14056 }
14057 if (isset($p['FONT-FEATURE-SETTINGS'])) {
14058 $css .= 'font-feature-settings: ' . strtolower($p['FONT-FEATURE-SETTINGS']) . '; ';
14059 }
14060 if (isset($p['FONT-LANGUAGE-OVERRIDE'])) {
14061 $css .= 'font-language-override: ' . strtolower($p['FONT-LANGUAGE-OVERRIDE']) . '; ';
14062 }
14063 if (isset($p['FONT-KERNING'])) {
14064 $css .= 'font-kerning: ' . strtolower($p['FONT-KERNING']) . '; ';
14065 }
14066
14067 if (isset($p['COLOR'])) {
14068 $css .= 'color: ' . strtolower($p['COLOR']) . '; ';
14069 }
14070 if (isset($p['Z-INDEX'])) {
14071 $css .= 'z-index: ' . $p['Z-INDEX'] . '; ';
14072 }
14073 if ($css) {
14074 $html = '<div style="' . $css . '">' . $html . '</div>';
14075 }
14076 // Copy over (only) the properties to set for border and background
14077 $pb = [];
14078 $pb['MARGIN-TOP'] = (isset($p['MARGIN-TOP']) ? $p['MARGIN-TOP'] : '');
14079 $pb['MARGIN-RIGHT'] = (isset($p['MARGIN-RIGHT']) ? $p['MARGIN-RIGHT'] : '');
14080 $pb['MARGIN-BOTTOM'] = (isset($p['MARGIN-BOTTOM']) ? $p['MARGIN-BOTTOM'] : '');
14081 $pb['MARGIN-LEFT'] = (isset($p['MARGIN-LEFT']) ? $p['MARGIN-LEFT'] : '');
14082 $pb['PADDING-TOP'] = (isset($p['PADDING-TOP']) ? $p['PADDING-TOP'] : '');
14083 $pb['PADDING-RIGHT'] = (isset($p['PADDING-RIGHT']) ? $p['PADDING-RIGHT'] : '');
14084 $pb['PADDING-BOTTOM'] = (isset($p['PADDING-BOTTOM']) ? $p['PADDING-BOTTOM'] : '');
14085 $pb['PADDING-LEFT'] = (isset($p['PADDING-LEFT']) ? $p['PADDING-LEFT'] : '');
14086 $pb['BORDER-TOP'] = (isset($p['BORDER-TOP']) ? $p['BORDER-TOP'] : '');
14087 $pb['BORDER-RIGHT'] = (isset($p['BORDER-RIGHT']) ? $p['BORDER-RIGHT'] : '');
14088 $pb['BORDER-BOTTOM'] = (isset($p['BORDER-BOTTOM']) ? $p['BORDER-BOTTOM'] : '');
14089 $pb['BORDER-LEFT'] = (isset($p['BORDER-LEFT']) ? $p['BORDER-LEFT'] : '');
14090 if (isset($p['BORDER-TOP-LEFT-RADIUS-H'])) {
14091 $pb['BORDER-TOP-LEFT-RADIUS-H'] = $p['BORDER-TOP-LEFT-RADIUS-H'];
14092 }
14093 if (isset($p['BORDER-TOP-LEFT-RADIUS-V'])) {
14094 $pb['BORDER-TOP-LEFT-RADIUS-V'] = $p['BORDER-TOP-LEFT-RADIUS-V'];
14095 }
14096 if (isset($p['BORDER-TOP-RIGHT-RADIUS-H'])) {
14097 $pb['BORDER-TOP-RIGHT-RADIUS-H'] = $p['BORDER-TOP-RIGHT-RADIUS-H'];
14098 }
14099 if (isset($p['BORDER-TOP-RIGHT-RADIUS-V'])) {
14100 $pb['BORDER-TOP-RIGHT-RADIUS-V'] = $p['BORDER-TOP-RIGHT-RADIUS-V'];
14101 }
14102 if (isset($p['BORDER-BOTTOM-LEFT-RADIUS-H'])) {
14103 $pb['BORDER-BOTTOM-LEFT-RADIUS-H'] = $p['BORDER-BOTTOM-LEFT-RADIUS-H'];
14104 }
14105 if (isset($p['BORDER-BOTTOM-LEFT-RADIUS-V'])) {
14106 $pb['BORDER-BOTTOM-LEFT-RADIUS-V'] = $p['BORDER-BOTTOM-LEFT-RADIUS-V'];
14107 }
14108 if (isset($p['BORDER-BOTTOM-RIGHT-RADIUS-H'])) {
14109 $pb['BORDER-BOTTOM-RIGHT-RADIUS-H'] = $p['BORDER-BOTTOM-RIGHT-RADIUS-H'];
14110 }
14111 if (isset($p['BORDER-BOTTOM-RIGHT-RADIUS-V'])) {
14112 $pb['BORDER-BOTTOM-RIGHT-RADIUS-V'] = $p['BORDER-BOTTOM-RIGHT-RADIUS-V'];
14113 }
14114 if (isset($p['BACKGROUND-COLOR'])) {
14115 $pb['BACKGROUND-COLOR'] = $p['BACKGROUND-COLOR'];
14116 }
14117 if (isset($p['BOX-SHADOW'])) {
14118 $pb['BOX-SHADOW'] = $p['BOX-SHADOW'];
14119 }
14120 /* -- BACKGROUNDS -- */
14121 if (isset($p['BACKGROUND-IMAGE'])) {
14122 $pb['BACKGROUND-IMAGE'] = $p['BACKGROUND-IMAGE'];
14123 }
14124 if (isset($p['BACKGROUND-IMAGE-RESIZE'])) {
14125 $pb['BACKGROUND-IMAGE-RESIZE'] = $p['BACKGROUND-IMAGE-RESIZE'];
14126 }
14127 if (isset($p['BACKGROUND-IMAGE-OPACITY'])) {
14128 $pb['BACKGROUND-IMAGE-OPACITY'] = $p['BACKGROUND-IMAGE-OPACITY'];
14129 }
14130 if (isset($p['BACKGROUND-REPEAT'])) {
14131 $pb['BACKGROUND-REPEAT'] = $p['BACKGROUND-REPEAT'];
14132 }
14133 if (isset($p['BACKGROUND-POSITION'])) {
14134 $pb['BACKGROUND-POSITION'] = $p['BACKGROUND-POSITION'];
14135 }
14136 if (isset($p['BACKGROUND-GRADIENT'])) {
14137 $pb['BACKGROUND-GRADIENT'] = $p['BACKGROUND-GRADIENT'];
14138 }
14139 if (isset($p['BACKGROUND-SIZE'])) {
14140 $pb['BACKGROUND-SIZE'] = $p['BACKGROUND-SIZE'];
14141 }
14142 if (isset($p['BACKGROUND-ORIGIN'])) {
14143 $pb['BACKGROUND-ORIGIN'] = $p['BACKGROUND-ORIGIN'];
14144 }
14145 if (isset($p['BACKGROUND-CLIP'])) {
14146 $pb['BACKGROUND-CLIP'] = $p['BACKGROUND-CLIP'];
14147 }
14148
14149 /* -- END BACKGROUNDS -- */
14150
14151 $this->setCSS($pb, 'BLOCK', $tag);
14152
14153 // ================================================================
14154 $bbox_br = $this->blk[1]['border_right']['w'];
14155 $bbox_bl = $this->blk[1]['border_left']['w'];
14156 $bbox_bt = $this->blk[1]['border_top']['w'];
14157 $bbox_bb = $this->blk[1]['border_bottom']['w'];
14158 $bbox_pr = $this->blk[1]['padding_right'];
14159 $bbox_pl = $this->blk[1]['padding_left'];
14160 $bbox_pt = $this->blk[1]['padding_top'];
14161 $bbox_pb = $this->blk[1]['padding_bottom'];
14162 $bbox_mr = $this->blk[1]['margin_right'];
14163 if (isset($p['MARGIN-RIGHT']) && strtolower($p['MARGIN-RIGHT']) == 'auto') {
14164 $bbox_mr = 'auto';
14165 }
14166 $bbox_ml = $this->blk[1]['margin_left'];
14167 if (isset($p['MARGIN-LEFT']) && strtolower($p['MARGIN-LEFT']) == 'auto') {
14168 $bbox_ml = 'auto';
14169 }
14170 $bbox_mt = $this->blk[1]['margin_top'];
14171 if (isset($p['MARGIN-TOP']) && strtolower($p['MARGIN-TOP']) == 'auto') {
14172 $bbox_mt = 'auto';
14173 }
14174 $bbox_mb = $this->blk[1]['margin_bottom'];
14175 if (isset($p['MARGIN-BOTTOM']) && strtolower($p['MARGIN-BOTTOM']) == 'auto') {
14176 $bbox_mb = 'auto';
14177 }
14178 if (isset($p['LEFT']) && strtolower($p['LEFT']) != 'auto') {
14179 $bbox_left = $this->sizeConverter->convert($p['LEFT'], $cont_w, $this->FontSize, false);
14180 } else {
14181 $bbox_left = 'auto';
14182 }
14183 if (isset($p['TOP']) && strtolower($p['TOP']) != 'auto') {
14184 $bbox_top = $this->sizeConverter->convert($p['TOP'], $cont_h, $this->FontSize, false);
14185 } else {
14186 $bbox_top = 'auto';
14187 }
14188 if (isset($p['RIGHT']) && strtolower($p['RIGHT']) != 'auto') {
14189 $bbox_right = $this->sizeConverter->convert($p['RIGHT'], $cont_w, $this->FontSize, false);
14190 } else {
14191 $bbox_right = 'auto';
14192 }
14193 if (isset($p['BOTTOM']) && strtolower($p['BOTTOM']) != 'auto') {
14194 $bbox_bottom = $this->sizeConverter->convert($p['BOTTOM'], $cont_h, $this->FontSize, false);
14195 } else {
14196 $bbox_bottom = 'auto';
14197 }
14198 if (isset($p['WIDTH']) && strtolower($p['WIDTH']) != 'auto') {
14199 $inner_w = $this->sizeConverter->convert($p['WIDTH'], $cont_w, $this->FontSize, false);
14200 } else {
14201 $inner_w = 'auto';
14202 }
14203 if (isset($p['HEIGHT']) && strtolower($p['HEIGHT']) != 'auto') {
14204 $inner_h = $this->sizeConverter->convert($p['HEIGHT'], $cont_h, $this->FontSize, false);
14205 } else {
14206 $inner_h = 'auto';
14207 }
14208
14209 // If bottom or right pos are set and not left / top - save this to adjust rotated block later
14210 if ($rotate == 90 || $rotate == -90) { // mPDF 6
14211 if ($bbox_left === 'auto' && $bbox_right !== 'auto') {
14212 $rot_rpos = $bbox_right;
14213 } else {
14214 $rot_rpos = false;
14215 }
14216 if ($bbox_top === 'auto' && $bbox_bottom !== 'auto') {
14217 $rot_bpos = $bbox_bottom;
14218 } else {
14219 $rot_bpos = false;
14220 }
14221 }
14222
14223 // ================================================================
14224 if ($checkinnerhtml == '' && $inner_h === 'auto') {
14225 $inner_h = 0.0001;
14226 }
14227 if ($checkinnerhtml == '' && $inner_w === 'auto') {
14228 $inner_w = 2 * $this->GetCharWidth('W', false);
14229 }
14230 // ================================================================
14231 // Algorithm from CSS2.1 See http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-height
14232 // mPD 5.3.14
14233 // Special case (not CSS) if all not specified, centre vertically on page
14234 $bbox_top_orig = '';
14235 if ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom === 'auto' && $bbox_mt === 'auto' && $bbox_mb === 'auto') {
14236 $bbox_top_orig = $bbox_top;
14237 if ($bbox_mt === 'auto') {
14238 $bbox_mt = 0;
14239 }
14240 if ($bbox_mb === 'auto') {
14241 $bbox_mb = 0;
14242 }
14243 $bbox_top = $orig_y0 - $bbox_mt - $cont_y;
14244 // solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
14245 } // mPD 5.3.14
14246 elseif ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom === 'auto') {
14247 $bbox_top_orig = $bbox_top = $orig_y0 - $cont_y;
14248 if ($bbox_mt === 'auto') {
14249 $bbox_mt = 0;
14250 }
14251 if ($bbox_mb === 'auto') {
14252 $bbox_mb = 0;
14253 }
14254 // solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
14255 } elseif ($bbox_top !== 'auto' && $inner_h !== 'auto' && $bbox_bottom !== 'auto') {
14256 if ($bbox_mt === 'auto' && $bbox_mb === 'auto') {
14257 $x = $cont_h - $bbox_top - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_bottom;
14258 $bbox_mt = $bbox_mb = ($x / 2);
14259 } elseif ($bbox_mt === 'auto') {
14260 $bbox_mt = $cont_h - $bbox_top - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
14261 } elseif ($bbox_mb === 'auto') {
14262 $bbox_mb = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_bottom;
14263 } else {
14264 $bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
14265 }
14266 } else {
14267 if ($bbox_mt === 'auto') {
14268 $bbox_mt = 0;
14269 }
14270 if ($bbox_mb === 'auto') {
14271 $bbox_mb = 0;
14272 }
14273 if ($bbox_top === 'auto' && $inner_h === 'auto' && $bbox_bottom !== 'auto') {
14274 // solve for $bbox_top when content_h known - $inner_h=='auto' && $bbox_top =='auto'
14275 } elseif ($bbox_top === 'auto' && $bbox_bottom === 'auto' && $inner_h !== 'auto') {
14276 $bbox_top = $orig_y0 - $bbox_mt - $cont_y;
14277 $bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
14278 } elseif ($inner_h === 'auto' && $bbox_bottom === 'auto' && $bbox_top !== 'auto') {
14279 // solve for $bbox_bottom when content_h known - $inner_h=='auto' && $bbox_bottom=='auto'
14280 } elseif ($bbox_top === 'auto' && $inner_h !== 'auto' && $bbox_bottom !== 'auto') {
14281 $bbox_top = $cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt - $bbox_bottom;
14282 } elseif ($inner_h === 'auto' && $bbox_top !== 'auto' && $bbox_bottom !== 'auto') {
14283 $inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mt - $bbox_bottom;
14284 } elseif ($bbox_bottom === 'auto' && $bbox_top !== 'auto' && $inner_h !== 'auto') {
14285 $bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mt;
14286 }
14287 }
14288
14289 // THEN DO SAME FOR WIDTH
14290 // http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width
14291 if ($bbox_left === 'auto' && $inner_w === 'auto' && $bbox_right === 'auto') {
14292 if ($bbox_ml === 'auto') {
14293 $bbox_ml = 0;
14294 }
14295 if ($bbox_mr === 'auto') {
14296 $bbox_mr = 0;
14297 }
14298 // IF containing element RTL, should set $bbox_right
14299 $bbox_left = $orig_x0 - $bbox_ml - $cont_x;
14300 // solve for $bbox_right when content_w known - $inner_w=='auto' && $bbox_right=='auto'
14301 } elseif ($bbox_left !== 'auto' && $inner_w !== 'auto' && $bbox_right !== 'auto') {
14302 if ($bbox_ml === 'auto' && $bbox_mr === 'auto') {
14303 $x = $cont_w - $bbox_left - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_right;
14304 $bbox_ml = $bbox_mr = ($x / 2);
14305 } elseif ($bbox_ml === 'auto') {
14306 $bbox_ml = $cont_w - $bbox_left - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_mr - $bbox_right;
14307 } elseif ($bbox_mr === 'auto') {
14308 $bbox_mr = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_right;
14309 } else {
14310 $bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
14311 }
14312 } else {
14313 if ($bbox_ml === 'auto') {
14314 $bbox_ml = 0;
14315 }
14316 if ($bbox_mr === 'auto') {
14317 $bbox_mr = 0;
14318 }
14319 if ($bbox_left === 'auto' && $inner_w === 'auto' && $bbox_right !== 'auto') {
14320 // solve for $bbox_left when content_w known - $inner_w=='auto' && $bbox_left =='auto'
14321 } elseif ($bbox_left === 'auto' && $bbox_right === 'auto' && $inner_w !== 'auto') {
14322 // IF containing element RTL, should set $bbox_right
14323 $bbox_left = $orig_x0 - $bbox_ml - $cont_x;
14324 $bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
14325 } elseif ($inner_w === 'auto' && $bbox_right === 'auto' && $bbox_left !== 'auto') {
14326 // solve for $bbox_right when content_w known - $inner_w=='auto' && $bbox_right=='auto'
14327 } elseif ($bbox_left === 'auto' && $inner_w !== 'auto' && $bbox_right !== 'auto') {
14328 $bbox_left = $cont_w - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
14329 } elseif ($inner_w === 'auto' && $bbox_left !== 'auto' && $bbox_right !== 'auto') {
14330 $inner_w = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
14331 } elseif ($bbox_right === 'auto' && $bbox_left !== 'auto' && $inner_w !== 'auto') {
14332 $bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
14333 }
14334 }
14335
14336 // ================================================================
14337 // ================================================================
14338 /* -- BACKGROUNDS -- */
14339 if (isset($pb['BACKGROUND-IMAGE']) && $pb['BACKGROUND-IMAGE']) {
14340 $ret = $this->SetBackground($pb, $this->blk[1]['inner_width']);
14341 if ($ret) {
14342 $this->blk[1]['background-image'] = $ret;
14343 }
14344 }
14345 /* -- END BACKGROUNDS -- */
14346
14347 $bbox_top_auto = $bbox_top === 'auto';
14348 $bbox_left_auto = $bbox_left === 'auto';
14349 $bbox_right_auto = $bbox_right === 'auto';
14350 $bbox_bottom_auto = $bbox_bottom === 'auto';
14351
14352 $bbox_top = is_numeric($bbox_top) ? $bbox_top : 0;
14353 $bbox_left = is_numeric($bbox_left) ? $bbox_left : 0;
14354 $bbox_right = is_numeric($bbox_right) ? $bbox_right : 0;
14355 $bbox_bottom = is_numeric($bbox_bottom) ? $bbox_bottom : 0;
14356
14357 $y = $cont_y + $bbox_top + $bbox_mt + $bbox_bt + $bbox_pt;
14358 $h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
14359
14360 $x = $cont_x + $bbox_left + $bbox_ml + $bbox_bl + $bbox_pl;
14361 $w = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $bbox_pr - $bbox_br - $bbox_mr - $bbox_right;
14362
14363 // Set (temporary) values for x y w h to do first paint, if values are auto
14364 if ($inner_h === 'auto' && $bbox_top_auto) {
14365 $y = $cont_y + $bbox_mt + $bbox_bt + $bbox_pt;
14366 $h = $cont_h - ($bbox_bottom + $bbox_mt + $bbox_mb + $bbox_bt + $bbox_bb + $bbox_pt + $bbox_pb);
14367 } elseif ($inner_h === 'auto' && $bbox_bottom_auto) {
14368 $y = $cont_y + $bbox_top + $bbox_mt + $bbox_bt + $bbox_pt;
14369 $h = $cont_h - ($bbox_top + $bbox_mt + $bbox_mb + $bbox_bt + $bbox_bb + $bbox_pt + $bbox_pb);
14370 }
14371 if ($inner_w === 'auto' && $bbox_left_auto) {
14372 $x = $cont_x + $bbox_ml + $bbox_bl + $bbox_pl;
14373 $w = $cont_w - ($bbox_right + $bbox_ml + $bbox_mr + $bbox_bl + $bbox_br + $bbox_pl + $bbox_pr);
14374 } elseif ($inner_w === 'auto' && $bbox_right_auto) {
14375 $x = $cont_x + $bbox_left + $bbox_ml + $bbox_bl + $bbox_pl;
14376 $w = $cont_w - ($bbox_left + $bbox_ml + $bbox_mr + $bbox_bl + $bbox_br + $bbox_pl + $bbox_pr);
14377 }
14378
14379 $bbox_y = $cont_y + $bbox_top + $bbox_mt;
14380 $bbox_x = $cont_x + $bbox_left + $bbox_ml;
14381
14382 $saved_block1 = $this->blk[1];
14383
14384 unset($p);
14385 unset($pb);
14386
14387 // ================================================================
14388 if ($inner_w === 'auto') { // do a first write
14389 $this->lMargin = $x;
14390 $this->rMargin = $this->w - $w - $x;
14391
14392 // SET POSITION & FONT VALUES
14393 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
14394 $this->pageoutput[$this->page] = [];
14395 $this->x = $x;
14396 $this->y = $y;
14397 $this->HTMLheaderPageLinks = [];
14398 $this->HTMLheaderPageAnnots = [];
14399 $this->HTMLheaderPageForms = [];
14400 $this->pageBackgrounds = [];
14401 $this->maxPosR = 0;
14402 $this->maxPosL = $this->w; // For RTL
14403 $this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
14404 $inner_w = $this->maxPosR - $this->lMargin;
14405 if ($bbox_right_auto) {
14406 $bbox_right = $cont_w - $bbox_left - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml;
14407 } elseif ($bbox_left_auto) {
14408 $bbox_left = $cont_w - $bbox_ml - $bbox_bl - $bbox_pl - $inner_w - $bbox_pr - $bbox_br - $bbox_ml - $bbox_right;
14409 $bbox_x = $cont_x + $bbox_left + $bbox_ml;
14410 $inner_x = $bbox_x + $bbox_bl + $bbox_pl;
14411 $x = $inner_x;
14412 }
14413
14414 $w = $inner_w;
14415 $bbox_y = $cont_y + $bbox_top + $bbox_mt;
14416 $bbox_x = $cont_x + $bbox_left + $bbox_ml;
14417 }
14418
14419 if ($inner_h === 'auto') { // do a first write
14420
14421 $this->lMargin = $x;
14422 $this->rMargin = $this->w - $w - $x;
14423
14424 // SET POSITION & FONT VALUES
14425 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
14426 $this->pageoutput[$this->page] = [];
14427 $this->x = $x;
14428 $this->y = $y;
14429 $this->HTMLheaderPageLinks = [];
14430 $this->HTMLheaderPageAnnots = [];
14431 $this->HTMLheaderPageForms = [];
14432 $this->pageBackgrounds = [];
14433 $this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
14434 $inner_h = $this->y - $y;
14435
14436 if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
14437 if (($this->y + $bbox_pb + $bbox_bb) > ($cont_y + $cont_h)) {
14438 $adj = ($this->y + $bbox_pb + $bbox_bb) - ($cont_y + $cont_h);
14439 $inner_h -= $adj;
14440 }
14441 }
14442 if ($bbox_bottom_auto && $bbox_top_orig === 'auto') {
14443 $bbox_bottom = $bbox_top = ($cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb) / 2;
14444 if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
14445 if ($bbox_top < 0) {
14446 $bbox_top = 0;
14447 $inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
14448 }
14449 }
14450 $bbox_y = $cont_y + $bbox_top + $bbox_mt;
14451 $inner_y = $bbox_y + $bbox_bt + $bbox_pt;
14452 $y = $inner_y;
14453 } elseif ($bbox_bottom_auto) {
14454 $bbox_bottom = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb;
14455 } elseif ($bbox_top_auto) {
14456 $bbox_top = $cont_h - $bbox_mt - $bbox_bt - $bbox_pt - $inner_h - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
14457 if ($overflow != 'hidden' && $overflow != 'visible') { // constrained
14458 if ($bbox_top < 0) {
14459 $bbox_top = 0;
14460 $inner_h = $cont_h - $bbox_top - $bbox_mt - $bbox_bt - $bbox_pt - $bbox_pb - $bbox_bb - $bbox_mb - $bbox_bottom;
14461 }
14462 }
14463 $bbox_y = $cont_y + $bbox_top + $bbox_mt;
14464 $inner_y = $bbox_y + $bbox_bt + $bbox_pt;
14465 $y = $inner_y;
14466 }
14467 $h = $inner_h;
14468 $bbox_y = $cont_y + $bbox_top + $bbox_mt;
14469 $bbox_x = $cont_x + $bbox_left + $bbox_ml;
14470 }
14471
14472 $inner_w = $w;
14473 $inner_h = $h;
14474 }
14475
14476 $this->lMargin = $x;
14477 $this->rMargin = $this->w - $w - $x;
14478
14479 // SET POSITION & FONT VALUES
14480 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
14481 $this->pageoutput[$this->page] = [];
14482
14483 $this->x = $x;
14484 $this->y = $y;
14485
14486 $this->HTMLheaderPageLinks = [];
14487 $this->HTMLheaderPageAnnots = [];
14488 $this->HTMLheaderPageForms = [];
14489
14490 $this->pageBackgrounds = [];
14491
14492 $this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
14493
14494 $actual_h = $this->y - $y;
14495 $use_w = $w;
14496 $use_h = $h;
14497 $ratio = $actual_h / $use_w;
14498
14499 if ($overflow != 'hidden' && $overflow != 'visible') {
14500 $target = $h / $w;
14501 if ($target > 0) {
14502 if (($ratio / $target) > 1) {
14503 $nl = ceil($actual_h / $this->lineheight);
14504 $l = $use_w * $nl;
14505 $est_w = sqrt(($l * $this->lineheight) / $target) * 0.8;
14506 $use_w += ($est_w - $use_w) - ($w / 100);
14507 }
14508 $bpcstart = ($ratio / $target);
14509 $bpcctr = 1;
14510
14511 while (($ratio / $target) > 1) {
14512 // @log 'Auto-sizing fixed-position block $bpcctr++
14513
14514 $this->x = $x;
14515 $this->y = $y;
14516
14517 if (($ratio / $target) > 1.5 || ($ratio / $target) < 0.6) {
14518 $use_w += ($w / $this->incrementFPR1);
14519 } elseif (($ratio / $target) > 1.2 || ($ratio / $target) < 0.85) {
14520 $use_w += ($w / $this->incrementFPR2);
14521 } elseif (($ratio / $target) > 1.1 || ($ratio / $target) < 0.91) {
14522 $use_w += ($w / $this->incrementFPR3);
14523 } else {
14524 $use_w += ($w / $this->incrementFPR4);
14525 }
14526
14527 $use_h = $use_w * $target;
14528 $this->rMargin = $this->w - $use_w - $x;
14529 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
14530 $this->HTMLheaderPageLinks = [];
14531 $this->HTMLheaderPageAnnots = [];
14532 $this->HTMLheaderPageForms = [];
14533 $this->pageBackgrounds = [];
14534 $this->WriteHTML($html, HTMLParserMode::HTML_HEADER_BUFFER);
14535 $actual_h = $this->y - $y;
14536 $ratio = $actual_h / $use_w;
14537 }
14538 }
14539 }
14540
14541 $shrink_f = $w / $use_w;
14542
14543 // ================================================================
14544
14545 $this->pages[$this->page] .= '___BEFORE_BORDERS___';
14546 $block_s = $this->PrintPageBackgrounds(); // Save to print later inside clipping path
14547 $this->pageBackgrounds = [];
14548
14549 // ================================================================
14550
14551 if ($rotate == 90 || $rotate == -90) { // mPDF 6
14552 $prerotw = $bbox_bl + $bbox_pl + $inner_w + $bbox_pr + $bbox_br;
14553 $preroth = $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb;
14554 $rot_start = " q\n";
14555 if ($rotate == 90) {
14556 if ($rot_rpos !== false) {
14557 $adjw = $prerotw;
14558 } // width before rotation
14559 else {
14560 $adjw = $preroth;
14561 } // height before rotation
14562 if ($rot_bpos !== false) {
14563 $adjh = -$prerotw + $preroth;
14564 } else {
14565 $adjh = 0;
14566 }
14567 } else {
14568 if ($rot_rpos !== false) {
14569 $adjw = $prerotw - $preroth;
14570 } else {
14571 $adjw = 0;
14572 }
14573 if ($rot_bpos !== false) {
14574 $adjh = $preroth;
14575 } // height before rotation
14576 else {
14577 $adjh = $prerotw;
14578 } // width before rotation
14579 }
14580 $rot_start .= $this->transformTranslate($adjw, $adjh, true) . "\n";
14581 $rot_start .= $this->transformRotate($rotate, $bbox_x, $bbox_y, true) . "\n";
14582 $rot_end = " Q\n";
14583 } elseif ($rotate == 180) { // mPDF 6
14584 $rot_start = " q\n";
14585 $rot_start .= $this->transformTranslate($bbox_bl + $bbox_pl + $inner_w + $bbox_pr + $bbox_br, $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb, true) . "\n";
14586 $rot_start .= $this->transformRotate(180, $bbox_x, $bbox_y, true) . "\n";
14587 $rot_end = " Q\n";
14588 } else {
14589 $rot_start = '';
14590 $rot_end = '';
14591 }
14592
14593 // ================================================================
14594 if (!empty($bounding)) {
14595 // WHEN HEIGHT // BOTTOM EDGE IS KNOWN and $this->y is set to the bottom
14596 // Re-instate saved $this->blk[1]
14597 $this->blk[1] = $saved_block1;
14598
14599 // These are only needed when painting border/background
14600 $this->blk[1]['width'] = $bbox_w = $cont_w - $bbox_left - $bbox_ml - $bbox_mr - $bbox_right;
14601 $this->blk[1]['x0'] = $bbox_x;
14602 $this->blk[1]['y0'] = $bbox_y;
14603 $this->blk[1]['startpage'] = $this->page;
14604 $this->blk[1]['y1'] = $bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb;
14605 $this->writer->write($rot_start);
14606 $this->PaintDivBB('', 0, 1); // Prints borders and sets backgrounds in $this->pageBackgrounds
14607 $this->writer->write($rot_end);
14608 }
14609
14610 $s = $this->PrintPageBackgrounds();
14611 $s = $rot_start . $s . $rot_end;
14612 $this->pages[$this->page] = preg_replace('/___BEFORE_BORDERS___/', "\n" . $s . "\n", $this->pages[$this->page]);
14613 $this->pageBackgrounds = [];
14614
14615 $this->writer->write($rot_start);
14616
14617 // Clipping Output
14618 if ($overflow == 'hidden') {
14619 // Bounding rectangle to clip
14620 $clip_y1 = $this->y;
14621 if (!empty($bounding) && ($this->y + $bbox_pb + $bbox_bb) > ($bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb )) {
14622 $clip_y1 = ($bbox_y + $bbox_bt + $bbox_pt + $inner_h + $bbox_pb + $bbox_bb ) - ($bbox_pb + $bbox_bb);
14623 }
14624 // $op = 'W* n'; // Clipping
14625 $op = 'W n'; // Clipping alternative mode
14626 $this->writer->write("q");
14627 $ch = $clip_y1 - $y;
14628 $this->writer->write(sprintf('%.3F %.3F %.3F %.3F re %s', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $w * Mpdf::SCALE, -$ch * Mpdf::SCALE, $op));
14629 if (!empty($block_s)) {
14630 $tmp = "q\n" . sprintf('%.3F %.3F %.3F %.3F re %s', $x * Mpdf::SCALE, ($this->h - $y) * Mpdf::SCALE, $w * Mpdf::SCALE, -$ch * Mpdf::SCALE, $op);
14631 $tmp .= "\n" . $block_s . "\nQ";
14632 $block_s = $tmp;
14633 }
14634 }
14635
14636
14637 if (!empty($block_s)) {
14638 if ($shrink_f != 1) { // i.e. autofit has resized the box
14639 $tmp = "q\n" . $this->transformScale(($shrink_f * 100), ($shrink_f * 100), $x, $y, true);
14640 $tmp .= "\n" . $block_s . "\nQ";
14641 $block_s = $tmp;
14642 }
14643 $this->writer->write($block_s);
14644 }
14645
14646
14647
14648 if ($shrink_f != 1) { // i.e. autofit has resized the box
14649 $this->StartTransform();
14650 $this->transformScale(($shrink_f * 100), ($shrink_f * 100), $x, $y);
14651 }
14652
14653 $this->writer->write($this->headerbuffer);
14654
14655 if ($shrink_f != 1) { // i.e. autofit has resized the box
14656 $this->StopTransform();
14657 }
14658
14659 if ($overflow == 'hidden') {
14660 // End clipping
14661 $this->writer->write("Q");
14662 }
14663
14664 $this->writer->write($rot_end);
14665
14666
14667 // Page Links
14668 foreach ($this->HTMLheaderPageLinks as $lk) {
14669 if ($rotate) {
14670 $tmp = $lk[2]; // Switch h - w
14671 $lk[2] = $lk[3];
14672 $lk[3] = $tmp;
14673
14674 $lx1 = (($lk[0] / Mpdf::SCALE));
14675 $ly1 = (($this->h - ($lk[1] / Mpdf::SCALE)));
14676 if ($rotate == 90) {
14677 $adjx = -($lx1 - $bbox_x) + ($preroth - ($ly1 - $bbox_y));
14678 $adjy = -($ly1 - $bbox_y) + ($lx1 - $bbox_x);
14679 $lk[2] = -$lk[2];
14680 } elseif ($rotate == -90) {
14681 $adjx = -($lx1 - $bbox_x) + ($ly1 - $bbox_y);
14682 $adjy = -($ly1 - $bbox_y) - ($lx1 - $bbox_x) + $prerotw;
14683 $lk[3] = -$lk[3];
14684 }
14685 if ($rot_rpos !== false) {
14686 $adjx += $prerotw - $preroth;
14687 }
14688 if ($rot_bpos !== false) {
14689 $adjy += $preroth - $prerotw;
14690 }
14691 $lx1 += $adjx;
14692 $ly1 += $adjy;
14693
14694 $lk[0] = $lx1 * Mpdf::SCALE;
14695 $lk[1] = ($this->h - $ly1) * Mpdf::SCALE;
14696 }
14697 if ($shrink_f != 1) { // i.e. autofit has resized the box
14698 $lx1 = (($lk[0] / Mpdf::SCALE) - $x);
14699 $lx2 = $x + ($lx1 * $shrink_f);
14700 $lk[0] = $lx2 * Mpdf::SCALE;
14701 $ly1 = (($this->h - ($lk[1] / Mpdf::SCALE)) - $y);
14702 $ly2 = $y + ($ly1 * $shrink_f);
14703 $lk[1] = ($this->h - $ly2) * Mpdf::SCALE;
14704 $lk[2] *= $shrink_f; // width
14705 $lk[3] *= $shrink_f; // height
14706 }
14707 $this->PageLinks[$this->page][] = $lk;
14708 }
14709
14710 foreach ($this->HTMLheaderPageForms as $n => $f) {
14711 if ($shrink_f != 1) { // i.e. autofit has resized the box
14712 $f['x'] = $x + (($f['x'] - $x) * $shrink_f);
14713 $f['y'] = $y + (($f['y'] - $y) * $shrink_f);
14714 $f['w'] *= $shrink_f;
14715 $f['h'] *= $shrink_f;
14716 $f['style']['fontsize'] *= $shrink_f;
14717 }
14718 $this->form->forms[$f['n']] = $f;
14719 }
14720 // Page Annotations
14721 foreach ($this->HTMLheaderPageAnnots as $lk) {
14722 if ($rotate) {
14723 if ($rotate == 90) {
14724 $adjx = -($lk['x'] - $bbox_x) + ($preroth - ($lk['y'] - $bbox_y));
14725 $adjy = -($lk['y'] - $bbox_y) + ($lk['x'] - $bbox_x);
14726 } elseif ($rotate == -90) {
14727 $adjx = -($lk['x'] - $bbox_x) + ($lk['y'] - $bbox_y);
14728 $adjy = -($lk['y'] - $bbox_y) - ($lk['x'] - $bbox_x) + $prerotw;
14729 }
14730 if ($rot_rpos !== false) {
14731 $adjx += $prerotw - $preroth;
14732 }
14733 if ($rot_bpos !== false) {
14734 $adjy += $preroth - $prerotw;
14735 }
14736 $lk['x'] += $adjx;
14737 $lk['y'] += $adjy;
14738 }
14739 if ($shrink_f != 1) { // i.e. autofit has resized the box
14740 $lk['x'] = $x + (($lk['x'] - $x) * $shrink_f);
14741 $lk['y'] = $y + (($lk['y'] - $y) * $shrink_f);
14742 }
14743 $this->PageAnnots[$this->page][] = $lk;
14744 }
14745
14746 // Restore
14747 $this->headerbuffer = '';
14748 $this->HTMLheaderPageLinks = [];
14749 $this->HTMLheaderPageAnnots = [];
14750 $this->HTMLheaderPageForms = [];
14751 $this->pageBackgrounds = $save_bgs;
14752 $this->writingHTMLheader = false;
14753
14754 $this->writingHTMLfooter = false;
14755 $this->fullImageHeight = false;
14756 $this->ResetMargins();
14757 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
14758 $this->SetXY($save_x, $save_y);
14759 $this->title2annots = $save_annots; // *ANNOTATIONS*
14760 $this->InFooter = false; // turns back on autopagebreaks
14761 $this->pageoutput[$this->page] = [];
14762 $this->pageoutput[$this->page]['Font'] = '';
14763 /* -- COLUMNS -- */
14764 if ($save_cols) {
14765 $this->SetColumns($save_nbcol, $this->colvAlign, $this->ColGap);
14766 }
14767 /* -- END COLUMNS -- */
14768 }
14769
14770 /* -- END CSS-POSITION -- */
14771
14772 function initialiseBlock(&$blk)
14773 {
14774 $blk['margin_top'] = 0;
14775 $blk['margin_left'] = 0;
14776 $blk['margin_bottom'] = 0;
14777 $blk['margin_right'] = 0;
14778 $blk['padding_top'] = 0;
14779 $blk['padding_left'] = 0;
14780 $blk['padding_bottom'] = 0;
14781 $blk['padding_right'] = 0;
14782 $blk['border_top']['w'] = 0;
14783 $blk['border_left']['w'] = 0;
14784 $blk['border_bottom']['w'] = 0;
14785 $blk['border_right']['w'] = 0;
14786 $blk['direction'] = 'ltr';
14787 $blk['hide'] = false;
14788 $blk['outer_left_margin'] = 0;
14789 $blk['outer_right_margin'] = 0;
14790 $blk['cascadeCSS'] = [];
14791 $blk['block-align'] = false;
14792 $blk['bgcolor'] = false;
14793 $blk['page_break_after_avoid'] = false;
14794 $blk['keep_block_together'] = false;
14795 $blk['float'] = false;
14796 $blk['line_height'] = '';
14797 $blk['margin_collapse'] = false;
14798 }
14799
14800 function border_details($bd)
14801 {
14802 $prop = preg_split('/\s+/', trim($bd));
14803
14804 if (isset($this->blk[$this->blklvl]['inner_width'])) {
14805 $refw = $this->blk[$this->blklvl]['inner_width'];
14806 } elseif (isset($this->blk[$this->blklvl - 1]['inner_width'])) {
14807 $refw = $this->blk[$this->blklvl - 1]['inner_width'];
14808 } else {
14809 $refw = $this->w;
14810 }
14811 if (count($prop) == 1) {
14812 $bsize = $this->sizeConverter->convert($prop[0], $refw, $this->FontSize, false);
14813 if ($bsize > 0) {
14814 return ['s' => 1, 'w' => $bsize, 'c' => $this->colorConverter->convert(0, $this->PDFAXwarnings), 'style' => 'solid'];
14815 } else {
14816 return ['w' => 0, 's' => 0];
14817 }
14818 } elseif (count($prop) == 2) {
14819 // 1px solid
14820 if (in_array($prop[1], $this->borderstyles) || $prop[1] == 'none' || $prop[1] == 'hidden') {
14821 $prop[2] = '';
14822 } // solid #000000
14823 elseif (in_array($prop[0], $this->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden') {
14824 $prop[0] = '';
14825 $prop[1] = $prop[0];
14826 $prop[2] = $prop[1];
14827 } // 1px #000000
14828 else {
14829 $prop[1] = '';
14830 $prop[2] = $prop[1];
14831 }
14832 } elseif (count($prop) == 3) {
14833 // Change #000000 1px solid to 1px solid #000000 (proper)
14834 if (substr($prop[0], 0, 1) == '#') {
14835 $tmp = $prop[0];
14836 $prop[0] = $prop[1];
14837 $prop[1] = $prop[2];
14838 $prop[2] = $tmp;
14839 } // Change solid #000000 1px to 1px solid #000000 (proper)
14840 elseif (substr($prop[0], 1, 1) == '#') {
14841 $tmp = $prop[1];
14842 $prop[0] = $prop[2];
14843 $prop[1] = $prop[0];
14844 $prop[2] = $tmp;
14845 } // Change solid 1px #000000 to 1px solid #000000 (proper)
14846 elseif (in_array($prop[0], $this->borderstyles) || $prop[0] == 'none' || $prop[0] == 'hidden') {
14847 $tmp = $prop[0];
14848 $prop[0] = $prop[1];
14849 $prop[1] = $tmp;
14850 }
14851 } else {
14852 return ['w' => 0, 's' => 0];
14853 }
14854 // Size
14855 $bsize = $this->sizeConverter->convert($prop[0], $refw, $this->FontSize, false);
14856 // color
14857 $coul = $this->colorConverter->convert($prop[2], $this->PDFAXwarnings); // returns array
14858 // Style
14859 $prop[1] = strtolower($prop[1]);
14860 if (in_array($prop[1], $this->borderstyles) && $bsize > 0) {
14861 $on = 1;
14862 } elseif ($prop[1] == 'hidden') {
14863 $on = 1;
14864 $bsize = 0;
14865 $coul = '';
14866 } elseif ($prop[1] == 'none') {
14867 $on = 0;
14868 $bsize = 0;
14869 $coul = '';
14870 } else {
14871 $on = 0;
14872 $bsize = 0;
14873 $coul = '';
14874 $prop[1] = '';
14875 }
14876 return ['s' => $on, 'w' => $bsize, 'c' => $coul, 'style' => $prop[1], 'dom' => 0];
14877 }
14878
14879 /* -- END HTML-CSS -- */
14880
14881
14882 /* -- BORDER-RADIUS -- */
14883
14884 function _borderPadding($a, $b, &$px, &$py)
14885 {
14886 // $px and py are padding long axis (x) and short axis (y)
14887 $added = 0; // extra padding
14888
14889 $x = $a - $px;
14890 $y = $b - $py;
14891 // Check if Falls within ellipse of border radius
14892 if (( (($x + $added) * ($x + $added)) / ($a * $a) + (($y + $added) * ($y + $added)) / ($b * $b) ) <= 1) {
14893 return false;
14894 }
14895
14896 $t = atan2($y, $x);
14897
14898 $newx = $b / sqrt((($b * $b) / ($a * $a)) + ( tan($t) * tan($t) ));
14899 $newy = $a / sqrt((($a * $a) / ($b * $b)) + ( (1 / tan($t)) * (1 / tan($t)) ));
14900 $px = max($px, $a - $newx + $added);
14901 $py = max($py, $b - $newy + $added);
14902 }
14903
14904 /* -- END BORDER-RADIUS -- */
14905 /* -- HTML-CSS -- */
14906 /* -- CSS-PAGE -- */
14907
14908 function SetPagedMediaCSS($name, $first, $oddEven)
14909 {
14910 if ($oddEven == 'E') {
14911 if ($this->directionality == 'rtl') {
14912 $side = 'R';
14913 } else {
14914 $side = 'L';
14915 }
14916 } else {
14917 if ($this->directionality == 'rtl') {
14918 $side = 'L';
14919 } else {
14920 $side = 'R';
14921 }
14922 }
14923 $name = strtoupper($name);
14924 $p = [];
14925 $p['SIZE'] = 'AUTO';
14926
14927 // Uses mPDF original margins as default
14928 $p['MARGIN-RIGHT'] = strval($this->orig_rMargin) . 'mm';
14929 $p['MARGIN-LEFT'] = strval($this->orig_lMargin) . 'mm';
14930 $p['MARGIN-TOP'] = strval($this->orig_tMargin) . 'mm';
14931 $p['MARGIN-BOTTOM'] = strval($this->orig_bMargin) . 'mm';
14932 $p['MARGIN-HEADER'] = strval($this->orig_hMargin) . 'mm';
14933 $p['MARGIN-FOOTER'] = strval($this->orig_fMargin) . 'mm';
14934
14935 // Basic page + selector
14936 if (isset($this->cssManager->CSS['@PAGE'])) {
14937 $zp = $this->cssManager->CSS['@PAGE'];
14938 } else {
14939 $zp = [];
14940 }
14941 if (is_array($zp) && !empty($zp)) {
14942 $p = array_merge($p, $zp);
14943 }
14944
14945 if (isset($p['EVEN-HEADER-NAME']) && $oddEven == 'E') {
14946 $p['HEADER'] = $p['EVEN-HEADER-NAME'];
14947 unset($p['EVEN-HEADER-NAME']);
14948 }
14949 if (isset($p['ODD-HEADER-NAME']) && $oddEven != 'E') {
14950 $p['HEADER'] = $p['ODD-HEADER-NAME'];
14951 unset($p['ODD-HEADER-NAME']);
14952 }
14953 if (isset($p['EVEN-FOOTER-NAME']) && $oddEven == 'E') {
14954 $p['FOOTER'] = $p['EVEN-FOOTER-NAME'];
14955 unset($p['EVEN-FOOTER-NAME']);
14956 }
14957 if (isset($p['ODD-FOOTER-NAME']) && $oddEven != 'E') {
14958 $p['FOOTER'] = $p['ODD-FOOTER-NAME'];
14959 unset($p['ODD-FOOTER-NAME']);
14960 }
14961
14962 // If right/Odd page
14963 if (isset($this->cssManager->CSS['@PAGE>>PSEUDO>>RIGHT']) && $side == 'R') {
14964 $zp = $this->cssManager->CSS['@PAGE>>PSEUDO>>RIGHT'];
14965 } else {
14966 $zp = [];
14967 }
14968 if (isset($zp['SIZE'])) {
14969 unset($zp['SIZE']);
14970 }
14971 if (isset($zp['SHEET-SIZE'])) {
14972 unset($zp['SHEET-SIZE']);
14973 }
14974 // Disallow margin-left or -right on :LEFT or :RIGHT
14975 if (isset($zp['MARGIN-LEFT'])) {
14976 unset($zp['MARGIN-LEFT']);
14977 }
14978 if (isset($zp['MARGIN-RIGHT'])) {
14979 unset($zp['MARGIN-RIGHT']);
14980 }
14981 if (is_array($zp) && !empty($zp)) {
14982 $p = array_merge($p, $zp);
14983 }
14984
14985 // If left/Even page
14986 if (isset($this->cssManager->CSS['@PAGE>>PSEUDO>>LEFT']) && $side == 'L') {
14987 $zp = $this->cssManager->CSS['@PAGE>>PSEUDO>>LEFT'];
14988 } else {
14989 $zp = [];
14990 }
14991 if (isset($zp['SIZE'])) {
14992 unset($zp['SIZE']);
14993 }
14994 if (isset($zp['SHEET-SIZE'])) {
14995 unset($zp['SHEET-SIZE']);
14996 }
14997 // Disallow margin-left or -right on :LEFT or :RIGHT
14998 if (isset($zp['MARGIN-LEFT'])) {
14999 unset($zp['MARGIN-LEFT']);
15000 }
15001 if (isset($zp['MARGIN-RIGHT'])) {
15002 unset($zp['MARGIN-RIGHT']);
15003 }
15004 if (is_array($zp) && !empty($zp)) {
15005 $p = array_merge($p, $zp);
15006 }
15007
15008 // If first page
15009 if (isset($this->cssManager->CSS['@PAGE>>PSEUDO>>FIRST']) && $first) {
15010 $zp = $this->cssManager->CSS['@PAGE>>PSEUDO>>FIRST'];
15011 } else {
15012 $zp = [];
15013 }
15014 if (isset($zp['SIZE'])) {
15015 unset($zp['SIZE']);
15016 }
15017 if (isset($zp['SHEET-SIZE'])) {
15018 unset($zp['SHEET-SIZE']);
15019 }
15020 // Disallow margin-left or -right on :FIRST // mPDF 5.7.3
15021 if (isset($zp['MARGIN-LEFT'])) {
15022 unset($zp['MARGIN-LEFT']);
15023 }
15024 if (isset($zp['MARGIN-RIGHT'])) {
15025 unset($zp['MARGIN-RIGHT']);
15026 }
15027 if (is_array($zp) && !empty($zp)) {
15028 $p = array_merge($p, $zp);
15029 }
15030
15031 // If named page
15032 if ($name) {
15033 if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name])) {
15034 $zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name];
15035 } else {
15036 $zp = [];
15037 }
15038 if (is_array($zp) && !empty($zp)) {
15039 $p = array_merge($p, $zp);
15040 }
15041
15042 if (isset($p['EVEN-HEADER-NAME']) && $oddEven == 'E') {
15043 $p['HEADER'] = $p['EVEN-HEADER-NAME'];
15044 unset($p['EVEN-HEADER-NAME']);
15045 }
15046 if (isset($p['ODD-HEADER-NAME']) && $oddEven != 'E') {
15047 $p['HEADER'] = $p['ODD-HEADER-NAME'];
15048 unset($p['ODD-HEADER-NAME']);
15049 }
15050 if (isset($p['EVEN-FOOTER-NAME']) && $oddEven == 'E') {
15051 $p['FOOTER'] = $p['EVEN-FOOTER-NAME'];
15052 unset($p['EVEN-FOOTER-NAME']);
15053 }
15054 if (isset($p['ODD-FOOTER-NAME']) && $oddEven != 'E') {
15055 $p['FOOTER'] = $p['ODD-FOOTER-NAME'];
15056 unset($p['ODD-FOOTER-NAME']);
15057 }
15058
15059 // If named right/Odd page
15060 if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>RIGHT']) && $side == 'R') {
15061 $zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>RIGHT'];
15062 } else {
15063 $zp = [];
15064 }
15065 if (isset($zp['SIZE'])) {
15066 unset($zp['SIZE']);
15067 }
15068 if (isset($zp['SHEET-SIZE'])) {
15069 unset($zp['SHEET-SIZE']);
15070 }
15071 // Disallow margin-left or -right on :LEFT or :RIGHT
15072 if (isset($zp['MARGIN-LEFT'])) {
15073 unset($zp['MARGIN-LEFT']);
15074 }
15075 if (isset($zp['MARGIN-RIGHT'])) {
15076 unset($zp['MARGIN-RIGHT']);
15077 }
15078 if (is_array($zp) && !empty($zp)) {
15079 $p = array_merge($p, $zp);
15080 }
15081
15082 // If named left/Even page
15083 if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>LEFT']) && $side == 'L') {
15084 $zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>LEFT'];
15085 } else {
15086 $zp = [];
15087 }
15088 if (isset($zp['SIZE'])) {
15089 unset($zp['SIZE']);
15090 }
15091 if (isset($zp['SHEET-SIZE'])) {
15092 unset($zp['SHEET-SIZE']);
15093 }
15094 // Disallow margin-left or -right on :LEFT or :RIGHT
15095 if (isset($zp['MARGIN-LEFT'])) {
15096 unset($zp['MARGIN-LEFT']);
15097 }
15098 if (isset($zp['MARGIN-RIGHT'])) {
15099 unset($zp['MARGIN-RIGHT']);
15100 }
15101 if (is_array($zp) && !empty($zp)) {
15102 $p = array_merge($p, $zp);
15103 }
15104
15105 // If named first page
15106 if (isset($this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>FIRST']) && $first) {
15107 $zp = $this->cssManager->CSS['@PAGE>>NAMED>>' . $name . '>>PSEUDO>>FIRST'];
15108 } else {
15109 $zp = [];
15110 }
15111 if (isset($zp['SIZE'])) {
15112 unset($zp['SIZE']);
15113 }
15114 if (isset($zp['SHEET-SIZE'])) {
15115 unset($zp['SHEET-SIZE']);
15116 }
15117 // Disallow margin-left or -right on :FIRST // mPDF 5.7.3
15118 if (isset($zp['MARGIN-LEFT'])) {
15119 unset($zp['MARGIN-LEFT']);
15120 }
15121 if (isset($zp['MARGIN-RIGHT'])) {
15122 unset($zp['MARGIN-RIGHT']);
15123 }
15124 if (is_array($zp) && !empty($zp)) {
15125 $p = array_merge($p, $zp);
15126 }
15127 }
15128
15129 $orientation = $mgl = $mgr = $mgt = $mgb = $mgh = $mgf = '';
15130 $header = $footer = '';
15131 $resetpagenum = $pagenumstyle = $suppress = '';
15132 $marks = '';
15133 $bg = [];
15134
15135 $newformat = '';
15136
15137
15138 if (isset($p['SHEET-SIZE']) && is_array($p['SHEET-SIZE'])) {
15139 $newformat = $p['SHEET-SIZE'];
15140 if ($newformat[0] > $newformat[1]) { // landscape
15141 $newformat = array_reverse($newformat);
15142 $p['ORIENTATION'] = 'L';
15143 } else {
15144 $p['ORIENTATION'] = 'P';
15145 }
15146 $this->_setPageSize($newformat, $p['ORIENTATION']);
15147 }
15148
15149 if (isset($p['SIZE']) && is_array($p['SIZE']) && !$newformat) {
15150 if ($p['SIZE']['W'] > $p['SIZE']['H']) {
15151 $p['ORIENTATION'] = 'L';
15152 } else {
15153 $p['ORIENTATION'] = 'P';
15154 }
15155 }
15156 if (is_array($p['SIZE'])) {
15157 if ($p['SIZE']['W'] > $this->fw) {
15158 $p['SIZE']['W'] = $this->fw;
15159 } // mPD 4.2 use fw not fPt
15160 if ($p['SIZE']['H'] > $this->fh) {
15161 $p['SIZE']['H'] = $this->fh;
15162 }
15163 if (($p['ORIENTATION'] == $this->DefOrientation && !$newformat) || ($newformat && $p['ORIENTATION'] == 'P')) {
15164 $outer_width_LR = ($this->fw - $p['SIZE']['W']) / 2;
15165 $outer_width_TB = ($this->fh - $p['SIZE']['H']) / 2;
15166 } else {
15167 $outer_width_LR = ($this->fh - $p['SIZE']['W']) / 2;
15168 $outer_width_TB = ($this->fw - $p['SIZE']['H']) / 2;
15169 }
15170 $pgw = $p['SIZE']['W'];
15171 $pgh = $p['SIZE']['H'];
15172 } else { // AUTO LANDSCAPE PORTRAIT
15173 $outer_width_LR = 0;
15174 $outer_width_TB = 0;
15175 if (!$newformat) {
15176 if (strtoupper($p['SIZE']) == 'AUTO') {
15177 $p['ORIENTATION'] = $this->DefOrientation;
15178 } elseif (strtoupper($p['SIZE']) == 'LANDSCAPE') {
15179 $p['ORIENTATION'] = 'L';
15180 } else {
15181 $p['ORIENTATION'] = 'P';
15182 }
15183 }
15184 if (($p['ORIENTATION'] == $this->DefOrientation && !$newformat) || ($newformat && $p['ORIENTATION'] == 'P')) {
15185 $pgw = $this->fw;
15186 $pgh = $this->fh;
15187 } else {
15188 $pgw = $this->fh;
15189 $pgh = $this->fw;
15190 }
15191 }
15192
15193 if (isset($p['HEADER']) && $p['HEADER']) {
15194 $header = $p['HEADER'];
15195 }
15196 if (isset($p['FOOTER']) && $p['FOOTER']) {
15197 $footer = $p['FOOTER'];
15198 }
15199 if (isset($p['RESETPAGENUM']) && $p['RESETPAGENUM']) {
15200 $resetpagenum = $p['RESETPAGENUM'];
15201 }
15202 if (isset($p['PAGENUMSTYLE']) && $p['PAGENUMSTYLE']) {
15203 $pagenumstyle = $p['PAGENUMSTYLE'];
15204 }
15205 if (isset($p['SUPPRESS']) && $p['SUPPRESS']) {
15206 $suppress = $p['SUPPRESS'];
15207 }
15208
15209 if (isset($p['MARKS'])) {
15210 if (preg_match('/cross/i', $p['MARKS']) && preg_match('/crop/i', $p['MARKS'])) {
15211 $marks = 'CROPCROSS';
15212 } elseif (strtoupper($p['MARKS']) == 'CROP') {
15213 $marks = 'CROP';
15214 } elseif (strtoupper($p['MARKS']) == 'CROSS') {
15215 $marks = 'CROSS';
15216 }
15217 }
15218
15219 if (isset($p['BACKGROUND-COLOR']) && $p['BACKGROUND-COLOR']) {
15220 $bg['BACKGROUND-COLOR'] = $p['BACKGROUND-COLOR'];
15221 }
15222 /* -- BACKGROUNDS -- */
15223 if (isset($p['BACKGROUND-GRADIENT']) && $p['BACKGROUND-GRADIENT']) {
15224 $bg['BACKGROUND-GRADIENT'] = $p['BACKGROUND-GRADIENT'];
15225 }
15226 if (isset($p['BACKGROUND-IMAGE']) && $p['BACKGROUND-IMAGE']) {
15227 $bg['BACKGROUND-IMAGE'] = $p['BACKGROUND-IMAGE'];
15228 }
15229 if (isset($p['BACKGROUND-REPEAT']) && $p['BACKGROUND-REPEAT']) {
15230 $bg['BACKGROUND-REPEAT'] = $p['BACKGROUND-REPEAT'];
15231 }
15232 if (isset($p['BACKGROUND-POSITION']) && $p['BACKGROUND-POSITION']) {
15233 $bg['BACKGROUND-POSITION'] = $p['BACKGROUND-POSITION'];
15234 }
15235 if (isset($p['BACKGROUND-IMAGE-RESIZE']) && $p['BACKGROUND-IMAGE-RESIZE']) {
15236 $bg['BACKGROUND-IMAGE-RESIZE'] = $p['BACKGROUND-IMAGE-RESIZE'];
15237 }
15238 if (isset($p['BACKGROUND-IMAGE-OPACITY'])) {
15239 $bg['BACKGROUND-IMAGE-OPACITY'] = $p['BACKGROUND-IMAGE-OPACITY'];
15240 }
15241 /* -- END BACKGROUNDS -- */
15242
15243 if (isset($p['MARGIN-LEFT'])) {
15244 $mgl = $this->sizeConverter->convert($p['MARGIN-LEFT'], $pgw) + $outer_width_LR;
15245 }
15246 if (isset($p['MARGIN-RIGHT'])) {
15247 $mgr = $this->sizeConverter->convert($p['MARGIN-RIGHT'], $pgw) + $outer_width_LR;
15248 }
15249 if (isset($p['MARGIN-BOTTOM'])) {
15250 $mgb = $this->sizeConverter->convert($p['MARGIN-BOTTOM'], $pgh) + $outer_width_TB;
15251 }
15252 if (isset($p['MARGIN-TOP'])) {
15253 $mgt = $this->sizeConverter->convert($p['MARGIN-TOP'], $pgh) + $outer_width_TB;
15254 }
15255 if (isset($p['MARGIN-HEADER'])) {
15256 $mgh = $this->sizeConverter->convert($p['MARGIN-HEADER'], $pgh) + $outer_width_TB;
15257 }
15258 if (isset($p['MARGIN-FOOTER'])) {
15259 $mgf = $this->sizeConverter->convert($p['MARGIN-FOOTER'], $pgh) + $outer_width_TB;
15260 }
15261
15262 if (isset($p['ORIENTATION']) && $p['ORIENTATION']) {
15263 $orientation = $p['ORIENTATION'];
15264 }
15265 $this->page_box['outer_width_LR'] = $outer_width_LR; // Used in MARKS:crop etc.
15266 $this->page_box['outer_width_TB'] = $outer_width_TB;
15267
15268 return [$orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $header, $footer, $bg, $resetpagenum, $pagenumstyle, $suppress, $marks, $newformat];
15269 }
15270
15271 /* -- END CSS-PAGE -- */
15272
15273
15274
15275 /* -- CSS-FLOAT -- */
15276
15277 // Added mPDF 3.0 Float DIV - CLEAR
15278 function ClearFloats($clear, $blklvl = 0)
15279 {
15280 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($blklvl, true);
15281 $end = $currpos = ($this->page * 1000 + $this->y);
15282 if ($clear == 'BOTH' && ($l_exists || $r_exists)) {
15283 $this->pageoutput[$this->page] = [];
15284 $end = max($l_max, $r_max, $currpos);
15285 } elseif ($clear == 'RIGHT' && $r_exists) {
15286 $this->pageoutput[$this->page] = [];
15287 $end = max($r_max, $currpos);
15288 } elseif ($clear == 'LEFT' && $l_exists) {
15289 $this->pageoutput[$this->page] = [];
15290 $end = max($l_max, $currpos);
15291 } else {
15292 return;
15293 }
15294 $old_page = $this->page;
15295 $new_page = intval($end / 1000);
15296 if ($old_page != $new_page) {
15297 $s = $this->PrintPageBackgrounds();
15298 // Writes after the marker so not overwritten later by page background etc.
15299 $this->pages[$this->page] = preg_replace('/(___BACKGROUND___PATTERNS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
15300 $this->pageBackgrounds = [];
15301 $this->page = $new_page;
15302 }
15303 $this->ResetMargins();
15304 $this->pageoutput[$this->page] = [];
15305
15306 $this->y = (round($end * 1000) % 1000000) / 1000; // mod changes operands to integers before processing
15307 }
15308
15309 // Added mPDF 3.0 Float DIV
15310 function GetFloatDivInfo($blklvl = 0, $clear = false)
15311 {
15312 // If blklvl specified, only returns floats at that level - for ClearFloats
15313 $l_exists = false;
15314 $r_exists = false;
15315 $l_max = 0;
15316 $r_max = 0;
15317 $l_width = 0;
15318 $r_width = 0;
15319 if (count($this->floatDivs)) {
15320 $currpos = ($this->page * 1000 + $this->y);
15321 foreach ($this->floatDivs as $f) {
15322 if (($clear && $f['blockContext'] == $this->blk[$blklvl]['blockContext']) || (!$clear && $currpos >= $f['startpos'] && $currpos < ($f['endpos'] - 0.001) && $f['blklvl'] > $blklvl && $f['blockContext'] == $this->blk[$blklvl]['blockContext'])) {
15323 if ($f['side'] == 'L') {
15324 $l_exists = true;
15325 $l_max = max($l_max, $f['endpos']);
15326 $l_width = max($l_width, $f['w']);
15327 }
15328 if ($f['side'] == 'R') {
15329 $r_exists = true;
15330 $r_max = max($r_max, $f['endpos']);
15331 $r_width = max($r_width, $f['w']);
15332 }
15333 }
15334 }
15335 }
15336 return [$l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width];
15337 }
15338
15339 /* -- END CSS-FLOAT -- */
15340
15341 // LIST MARKERS // mPDF 6 Lists
15342 function _setListMarker($listitemtype, $listitemimage, $listitemposition)
15343 {
15344 // if position:inside (and NOT table) - output now as a textbuffer; (so if next is block, will move to new line)
15345 // elseif position:outside (and NOT table) - output in front of first textbuffer output by setting listitem (cf. _saveTextBuffer)
15346 $e = '';
15347 $this->listitem = '';
15348 $spacer = ' ';
15349 // IMAGE
15350 if ($listitemimage && $listitemimage != 'none') {
15351 $listitemimage = trim(preg_replace('/url\‍(["\']*(.*?)["\']*\‍)/', '\\1', $listitemimage));
15352
15353 // ? Restrict maximum height/width of list marker??
15354 $maxWidth = 100;
15355 $maxHeight = 100;
15356
15357 $objattr = [];
15358 $objattr['margin_top'] = 0;
15359 $objattr['margin_bottom'] = 0;
15360 $objattr['margin_left'] = 0;
15361 $objattr['margin_right'] = 0;
15362 $objattr['padding_top'] = 0;
15363 $objattr['padding_bottom'] = 0;
15364 $objattr['padding_left'] = 0;
15365 $objattr['padding_right'] = 0;
15366 $objattr['width'] = 0;
15367 $objattr['height'] = 0;
15368 $objattr['border_top']['w'] = 0;
15369 $objattr['border_bottom']['w'] = 0;
15370 $objattr['border_left']['w'] = 0;
15371 $objattr['border_right']['w'] = 0;
15372 $objattr['visibility'] = 'visible';
15373 $srcpath = $listitemimage;
15374 $orig_srcpath = $listitemimage;
15375
15376 $objattr['vertical-align'] = 'BS'; // vertical alignment of marker (baseline)
15377 $w = 0;
15378 $h = 0;
15379
15380 // Image file
15381 $info = $this->imageProcessor->getImage($srcpath, true, true, $orig_srcpath);
15382 if (!$info) {
15383 return;
15384 }
15385
15386 if ($info['w'] == 0 && $info['h'] == 0) {
15387 $info['h'] = $this->sizeConverter->convert('1em', $this->blk[$this->blklvl]['inner_width'], $this->FontSize, false);
15388 }
15389
15390 $objattr['file'] = $srcpath;
15391
15392 // Default width and height calculation if needed
15393 if ($w == 0 and $h == 0) {
15394 /* -- IMAGES-WMF -- */
15395 if ($info['type'] == 'wmf') {
15396 // WMF units are twips (1/20pt)
15397 // divide by 20 to get points
15398 // divide by k to get user units
15399 $w = abs($info['w']) / (20 * Mpdf::SCALE);
15400 $h = abs($info['h']) / (20 * Mpdf::SCALE);
15401 } else { /* -- END IMAGES-WMF -- */
15402 if ($info['type'] == 'svg') {
15403 // SVG units are pixels
15404 $w = abs($info['w']) / Mpdf::SCALE;
15405 $h = abs($info['h']) / Mpdf::SCALE;
15406 } else {
15407 // Put image at default image dpi
15408 $w = ($info['w'] / Mpdf::SCALE) * (72 / $this->img_dpi);
15409 $h = ($info['h'] / Mpdf::SCALE) * (72 / $this->img_dpi);
15410 }
15411 }
15412 }
15413 // IF WIDTH OR HEIGHT SPECIFIED
15414 if ($w == 0) {
15415 $w = abs($h * $info['w'] / $info['h']);
15416 }
15417 if ($h == 0) {
15418 $h = abs($w * $info['h'] / $info['w']);
15419 }
15420
15421 if ($w > $maxWidth) {
15422 $w = $maxWidth;
15423 $h = abs($w * $info['h'] / $info['w']);
15424 }
15425
15426 if ($h > $maxHeight) {
15427 $h = $maxHeight;
15428 $w = abs($h * $info['w'] / $info['h']);
15429 }
15430
15431 $objattr['type'] = 'image';
15432 $objattr['itype'] = $info['type'];
15433
15434 $objattr['orig_h'] = $info['h'];
15435 $objattr['orig_w'] = $info['w'];
15436
15437 /* -- IMAGES-WMF -- */
15438 if ($info['type'] == 'wmf') {
15439 $objattr['wmf_x'] = $info['x'];
15440 $objattr['wmf_y'] = $info['y'];
15441 } else { /* -- END IMAGES-WMF -- */
15442 if ($info['type'] == 'svg') {
15443 $objattr['wmf_x'] = $info['x'];
15444 $objattr['wmf_y'] = $info['y'];
15445 }
15446 }
15447
15448 $objattr['height'] = $h;
15449 $objattr['width'] = $w;
15450 $objattr['image_height'] = $h;
15451 $objattr['image_width'] = $w;
15452
15453 $objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
15454 $objattr['listmarker'] = true;
15455
15456 $objattr['listmarkerposition'] = $listitemposition;
15457
15458 $e = "\xbb\xa4\xactype=image,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
15459 $this->_saveTextBuffer($e);
15460
15461 if ($listitemposition == 'inside') {
15462 $e = $spacer;
15463 $this->_saveTextBuffer($e);
15464 }
15465 } elseif ($listitemtype == 'disc' || $listitemtype == 'circle' || $listitemtype == 'square') { // SYMBOL (needs new font)
15466 $objattr = [];
15467 $objattr['type'] = 'listmarker';
15468 $objattr['listmarkerposition'] = $listitemposition;
15469 $objattr['width'] = 0;
15470 $size = $this->sizeConverter->convert($this->list_symbol_size, $this->FontSize);
15471 $objattr['size'] = $size;
15472 $objattr['offset'] = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
15473
15474 if ($listitemposition == 'inside') {
15475 $objattr['width'] = $size + $objattr['offset'];
15476 }
15477
15478 $objattr['height'] = $this->FontSize;
15479 $objattr['vertical-align'] = 'T';
15480 $objattr['text'] = '';
15481 $objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
15482 $objattr['bullet'] = $listitemtype;
15483 $objattr['colorarray'] = $this->colorarray;
15484 $objattr['fontfamily'] = $this->FontFamily;
15485 $objattr['fontsize'] = $this->FontSize;
15486 $objattr['fontsizept'] = $this->FontSizePt;
15487 $objattr['fontstyle'] = $this->FontStyle;
15488
15489 $e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
15490 $this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array
15491
15492 } elseif (preg_match('/U\+([a-fA-F0-9]+)/i', $listitemtype, $m)) { // SYMBOL 2 (needs new font)
15493
15494 if ($this->_charDefined($this->CurrentFont['cw'], hexdec($m[1]))) {
15495 $list_item_marker = UtfString::codeHex2utf($m[1]);
15496 } else {
15497 $list_item_marker = '-';
15498 }
15499 if (preg_match('/rgb\‍(.*?\‍)/', $listitemtype, $m)) {
15500 $list_item_color = $this->colorConverter->convert($m[0], $this->PDFAXwarnings);
15501 } else {
15502 $list_item_color = '';
15503 }
15504
15505 // SAVE then SET COLR
15506 $save_colorarray = $this->colorarray;
15507 if ($list_item_color) {
15508 $this->colorarray = $list_item_color;
15509 }
15510
15511 if ($listitemposition == 'inside') {
15512 $e = $list_item_marker . $spacer;
15513 $this->_saveTextBuffer($e);
15514 } else {
15515 $objattr = [];
15516 $objattr['type'] = 'listmarker';
15517 $objattr['width'] = 0;
15518 $objattr['height'] = $this->FontSize;
15519 $objattr['vertical-align'] = 'T';
15520 $objattr['text'] = $list_item_marker;
15521 $objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
15522 $objattr['colorarray'] = $this->colorarray;
15523 $objattr['fontfamily'] = $this->FontFamily;
15524 $objattr['fontsize'] = $this->FontSize;
15525 $objattr['fontsizept'] = $this->FontSizePt;
15526 $objattr['fontstyle'] = $this->FontStyle;
15527 $e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
15528 $this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array
15529 }
15530
15531 // RESET COLOR
15532 $this->colorarray = $save_colorarray;
15533
15534 } else { // TEXT
15535 $counter = $this->listcounter[$this->listlvl];
15536
15537 if ($listitemtype == 'none') {
15538 return;
15539 }
15540
15541 $num = $this->_getStyledNumber($counter, $listitemtype, true);
15542
15543 if ($listitemposition == 'inside') {
15544 $e = $num . $this->list_number_suffix . $spacer;
15545 $this->_saveTextBuffer($e);
15546 } else {
15547 if (isset($this->blk[$this->blklvl]['direction']) && $this->blk[$this->blklvl]['direction'] == 'rtl') {
15548 // REPLACE MIRRORED RTL $this->list_number_suffix e.g. ) -> ( (NB could use Ucdn::$mirror_pairs)
15549 $m = strtr($this->list_number_suffix, ")]}", "([{") . $num;
15550 } else {
15551 $m = $num . $this->list_number_suffix;
15552 }
15553
15554 $objattr = [];
15555 $objattr['type'] = 'listmarker';
15556 $objattr['width'] = 0;
15557 $objattr['height'] = $this->FontSize;
15558 $objattr['vertical-align'] = 'T';
15559 $objattr['text'] = $m;
15560 $objattr['dir'] = (isset($this->blk[$this->blklvl]['direction']) ? $this->blk[$this->blklvl]['direction'] : 'ltr');
15561 $objattr['colorarray'] = $this->colorarray;
15562 $objattr['fontfamily'] = $this->FontFamily;
15563 $objattr['fontsize'] = $this->FontSize;
15564 $objattr['fontsizept'] = $this->FontSizePt;
15565 $objattr['fontstyle'] = $this->FontStyle;
15566 $e = "\xbb\xa4\xactype=listmarker,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
15567
15568 $this->listitem = $this->_saveTextBuffer($e, '', '', true); // true returns array
15569 }
15570 }
15571 }
15572
15573 // mPDF Lists
15574 function _getListMarkerWidth(&$currblk, &$a, &$i)
15575 {
15576 $blt_width = 0;
15577
15578 $markeroffset = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
15579
15580 // Get Maximum number in the list
15581 $maxnum = $this->listcounter[$this->listlvl];
15582 if ($currblk['list_style_type'] != 'disc' && $currblk['list_style_type'] != 'circle' && $currblk['list_style_type'] != 'square') {
15583 $lvl = 1;
15584 for ($j = $i + 2; $j < count($a); $j+=2) {
15585 $e = $a[$j];
15586 if (!$e) {
15587 continue;
15588 }
15589 if ($e[0] == '/') { // end tag
15590 $e = strtoupper(substr($e, 1));
15591 if ($e == 'OL' || $e == 'UL') {
15592 if ($lvl == 1) {
15593 break;
15594 }
15595 $lvl--;
15596 }
15597 } else { // opening tag
15598 if (strpos($e, ' ')) {
15599 $e = substr($e, 0, strpos($e, ' '));
15600 }
15601 $e = strtoupper($e);
15602 if ($e == 'LI') {
15603 if ($lvl == 1) {
15604 $maxnum++;
15605 }
15606 } elseif ($e == 'OL' || $e == 'UL') {
15607 $lvl++;
15608 }
15609 }
15610 }
15611 }
15612
15613 $decToAlpha = new Conversion\DecToAlpha();
15614 $decToRoman = new Conversion\DecToRoman();
15615 $decToOther = new Conversion\DecToOther($this);
15616
15617 switch ($currblk['list_style_type']) {
15618 case 'decimal':
15619 case '1':
15620 $blt_width = $this->GetStringWidth(str_repeat('5', strlen($maxnum)) . $this->list_number_suffix);
15621 break;
15622 case 'none':
15623 $blt_width = 0;
15624 break;
15625 case 'upper-alpha':
15626 case 'upper-latin':
15627 case 'A':
15628 $maxnumA = $decToAlpha->convert($maxnum, true);
15629 if ($maxnum < 13) {
15630 $blt_width = $this->GetStringWidth('D' . $this->list_number_suffix);
15631 } else {
15632 $blt_width = $this->GetStringWidth(str_repeat('W', strlen($maxnumA)) . $this->list_number_suffix);
15633 }
15634 break;
15635 case 'lower-alpha':
15636 case 'lower-latin':
15637 case 'a':
15638 $maxnuma = $decToAlpha->convert($maxnum, false);
15639 if ($maxnum < 13) {
15640 $blt_width = $this->GetStringWidth('b' . $this->list_number_suffix);
15641 } else {
15642 $blt_width = $this->GetStringWidth(str_repeat('m', strlen($maxnuma)) . $this->list_number_suffix);
15643 }
15644 break;
15645 case 'upper-roman':
15646 case 'I':
15647 if ($maxnum > 87) {
15648 $bbit = 87;
15649 } elseif ($maxnum > 86) {
15650 $bbit = 86;
15651 } elseif ($maxnum > 37) {
15652 $bbit = 38;
15653 } elseif ($maxnum > 36) {
15654 $bbit = 37;
15655 } elseif ($maxnum > 27) {
15656 $bbit = 28;
15657 } elseif ($maxnum > 26) {
15658 $bbit = 27;
15659 } elseif ($maxnum > 17) {
15660 $bbit = 18;
15661 } elseif ($maxnum > 16) {
15662 $bbit = 17;
15663 } elseif ($maxnum > 7) {
15664 $bbit = 8;
15665 } elseif ($maxnum > 6) {
15666 $bbit = 7;
15667 } elseif ($maxnum > 3) {
15668 $bbit = 4;
15669 } else {
15670 $bbit = $maxnum;
15671 }
15672
15673 $maxlnum = $decToRoman->convert($bbit, true);
15674 $blt_width = $this->GetStringWidth($maxlnum . $this->list_number_suffix);
15675
15676 break;
15677 case 'lower-roman':
15678 case 'i':
15679 if ($maxnum > 87) {
15680 $bbit = 87;
15681 } elseif ($maxnum > 86) {
15682 $bbit = 86;
15683 } elseif ($maxnum > 37) {
15684 $bbit = 38;
15685 } elseif ($maxnum > 36) {
15686 $bbit = 37;
15687 } elseif ($maxnum > 27) {
15688 $bbit = 28;
15689 } elseif ($maxnum > 26) {
15690 $bbit = 27;
15691 } elseif ($maxnum > 17) {
15692 $bbit = 18;
15693 } elseif ($maxnum > 16) {
15694 $bbit = 17;
15695 } elseif ($maxnum > 7) {
15696 $bbit = 8;
15697 } elseif ($maxnum > 6) {
15698 $bbit = 7;
15699 } elseif ($maxnum > 3) {
15700 $bbit = 4;
15701 } else {
15702 $bbit = $maxnum;
15703 }
15704 $maxlnum = $decToRoman->convert($bbit, false);
15705 $blt_width = $this->GetStringWidth($maxlnum . $this->list_number_suffix);
15706 break;
15707
15708 case 'disc':
15709 case 'circle':
15710 case 'square':
15711 $size = $this->sizeConverter->convert($this->list_symbol_size, $this->FontSize);
15712 $offset = $this->sizeConverter->convert($this->list_marker_offset, $this->FontSize);
15713 $blt_width = $size + $offset;
15714 break;
15715
15716 case 'arabic-indic':
15717 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0660), strlen($maxnum)) . $this->list_number_suffix);
15718 break;
15719 case 'persian':
15720 case 'urdu':
15721 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x06F0), strlen($maxnum)) . $this->list_number_suffix);
15722 break;
15723 case 'bengali':
15724 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x09E6), strlen($maxnum)) . $this->list_number_suffix);
15725 break;
15726 case 'devanagari':
15727 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0966), strlen($maxnum)) . $this->list_number_suffix);
15728 break;
15729 case 'gujarati':
15730 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0AE6), strlen($maxnum)) . $this->list_number_suffix);
15731 break;
15732 case 'gurmukhi':
15733 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0A66), strlen($maxnum)) . $this->list_number_suffix);
15734 break;
15735 case 'kannada':
15736 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0CE6), strlen($maxnum)) . $this->list_number_suffix);
15737 break;
15738 case 'malayalam':
15739 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(6, 0x0D66), strlen($maxnum)) . $this->list_number_suffix);
15740 break;
15741 case 'oriya':
15742 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0B66), strlen($maxnum)) . $this->list_number_suffix);
15743 break;
15744 case 'telugu':
15745 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(3, 0x0C66), strlen($maxnum)) . $this->list_number_suffix);
15746 break;
15747 case 'tamil':
15748 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(9, 0x0BE6), strlen($maxnum)) . $this->list_number_suffix);
15749 break;
15750 case 'thai':
15751 $blt_width = $this->GetStringWidth(str_repeat($decToOther->convert(5, 0x0E50), strlen($maxnum)) . $this->list_number_suffix);
15752 break;
15753 default:
15754 $blt_width = $this->GetStringWidth(str_repeat('5', strlen($maxnum)) . $this->list_number_suffix);
15755 break;
15756 }
15757
15758 return ($blt_width + $markeroffset);
15759 }
15760
15761 function _saveTextBuffer($t, $link = '', $intlink = '', $return = false)
15762 {
15763 // mPDF 6 Lists
15764 $arr = [];
15765 $arr[0] = $t;
15766 if (isset($link) && $link) {
15767 $arr[1] = $link;
15768 }
15769 $arr[2] = $this->currentfontstyle;
15770 if (isset($this->colorarray) && $this->colorarray) {
15771 $arr[3] = $this->colorarray;
15772 }
15773 $arr[4] = $this->currentfontfamily;
15774 $arr[5] = $this->currentLang; // mPDF 6
15775 if (isset($intlink) && $intlink) {
15776 $arr[7] = $intlink;
15777 }
15778 // mPDF 6
15779 // If Kerning set for OTL, and useOTL has positive value, but has not set for this particular script,
15780 // set for kerning via kern table
15781 // e.g. Latin script when useOTL set as 0x80
15782 if (isset($this->OTLtags['Plus']) && strpos($this->OTLtags['Plus'], 'kern') !== false && empty($this->OTLdata['GPOSinfo'])) {
15783 $this->textvar = ($this->textvar | TextVars::FC_KERNING);
15784 }
15785 $arr[8] = $this->textvar; // mPDF 5.7.1
15786 if (isset($this->textparam) && $this->textparam) {
15787 $arr[9] = $this->textparam;
15788 }
15789 if (isset($this->spanbgcolorarray) && $this->spanbgcolorarray) {
15790 $arr[10] = $this->spanbgcolorarray;
15791 }
15792 $arr[11] = $this->currentfontsize;
15793 if (isset($this->ReqFontStyle) && $this->ReqFontStyle) {
15794 $arr[12] = $this->ReqFontStyle;
15795 }
15796 if (isset($this->lSpacingCSS) && $this->lSpacingCSS) {
15797 $arr[14] = $this->lSpacingCSS;
15798 }
15799 if (isset($this->wSpacingCSS) && $this->wSpacingCSS) {
15800 $arr[15] = $this->wSpacingCSS;
15801 }
15802 if (isset($this->spanborddet) && $this->spanborddet) {
15803 $arr[16] = $this->spanborddet;
15804 }
15805 if (isset($this->textshadow) && $this->textshadow) {
15806 $arr[17] = $this->textshadow;
15807 }
15808 if (isset($this->OTLdata) && $this->OTLdata) {
15809 $arr[18] = $this->OTLdata;
15810 $this->OTLdata = [];
15811 } // mPDF 5.7.1
15812 else {
15813 $arr[18] = null;
15814 }
15815 // mPDF 6 Lists
15816 if ($return) {
15817 return ($arr);
15818 }
15819 if ($this->listitem) {
15820 $this->textbuffer[] = $this->listitem;
15821 $this->listitem = [];
15822 }
15823 $this->textbuffer[] = $arr;
15824 }
15825
15826 function _saveCellTextBuffer($t, $link = '', $intlink = '')
15827 {
15828 $arr = [];
15829 $arr[0] = $t;
15830 if (isset($link) && $link) {
15831 $arr[1] = $link;
15832 }
15833 $arr[2] = $this->currentfontstyle;
15834 if (isset($this->colorarray) && $this->colorarray) {
15835 $arr[3] = $this->colorarray;
15836 }
15837 $arr[4] = $this->currentfontfamily;
15838 if (isset($intlink) && $intlink) {
15839 $arr[7] = $intlink;
15840 }
15841 // mPDF 6
15842 // If Kerning set for OTL, and useOTL has positive value, but has not set for this particular script,
15843 // set for kerning via kern table
15844 // e.g. Latin script when useOTL set as 0x80
15845 if (isset($this->OTLtags['Plus']) && strpos($this->OTLtags['Plus'], 'kern') !== false && empty($this->OTLdata['GPOSinfo'])) {
15846 $this->textvar = ($this->textvar | TextVars::FC_KERNING);
15847 }
15848 $arr[8] = $this->textvar; // mPDF 5.7.1
15849 if (isset($this->textparam) && $this->textparam) {
15850 $arr[9] = $this->textparam;
15851 }
15852 if (isset($this->spanbgcolorarray) && $this->spanbgcolorarray) {
15853 $arr[10] = $this->spanbgcolorarray;
15854 }
15855 $arr[11] = $this->currentfontsize;
15856 if (isset($this->ReqFontStyle) && $this->ReqFontStyle) {
15857 $arr[12] = $this->ReqFontStyle;
15858 }
15859 if (isset($this->lSpacingCSS) && $this->lSpacingCSS) {
15860 $arr[14] = $this->lSpacingCSS;
15861 }
15862 if (isset($this->wSpacingCSS) && $this->wSpacingCSS) {
15863 $arr[15] = $this->wSpacingCSS;
15864 }
15865 if (isset($this->spanborddet) && $this->spanborddet) {
15866 $arr[16] = $this->spanborddet;
15867 }
15868 if (isset($this->textshadow) && $this->textshadow) {
15869 $arr[17] = $this->textshadow;
15870 }
15871 if (isset($this->OTLdata) && $this->OTLdata) {
15872 $arr[18] = $this->OTLdata;
15873 $this->OTLdata = [];
15874 } // mPDF 5.7.1
15875 else {
15876 $arr[18] = null;
15877 }
15878 $this->cell[$this->row][$this->col]['textbuffer'][] = $arr;
15879 }
15880
15881 function printbuffer($arrayaux, $blockstate = 0, $is_table = false, $table_draft = false, $cell_dir = '')
15882 {
15883 // $blockstate = 0; // NO margins/padding
15884 // $blockstate = 1; // Top margins/padding only
15885 // $blockstate = 2; // Bottom margins/padding only
15886 // $blockstate = 3; // Top & bottom margins/padding
15887 $this->spanbgcolorarray = '';
15888 $this->spanbgcolor = false;
15889 $this->spanborder = false;
15890 $this->spanborddet = [];
15891 $paint_ht_corr = 0;
15892 /* -- CSS-FLOAT -- */
15893 if (count($this->floatDivs)) {
15894 list($l_exists, $r_exists, $l_max, $r_max, $l_width, $r_width) = $this->GetFloatDivInfo($this->blklvl);
15895 if (($this->blk[$this->blklvl]['inner_width'] - $l_width - $r_width) < (2 * $this->GetCharWidth('W', false))) {
15896 // Too narrow to fit - try to move down past L or R float
15897 if ($l_max < $r_max && ($this->blk[$this->blklvl]['inner_width'] - $r_width) > (2 * $this->GetCharWidth('W', false))) {
15898 $this->ClearFloats('LEFT', $this->blklvl);
15899 } elseif ($r_max < $l_max && ($this->blk[$this->blklvl]['inner_width'] - $l_width) > (2 * $this->GetCharWidth('W', false))) {
15900 $this->ClearFloats('RIGHT', $this->blklvl);
15901 } else {
15902 $this->ClearFloats('BOTH', $this->blklvl);
15903 }
15904 }
15905 }
15906 /* -- END CSS-FLOAT -- */
15907 $bak_y = $this->y;
15908 $bak_x = $this->x;
15909 $align = '';
15910 if (!$is_table) {
15911 if (isset($this->blk[$this->blklvl]['align']) && $this->blk[$this->blklvl]['align']) {
15912 $align = $this->blk[$this->blklvl]['align'];
15913 }
15914 // Block-align is set by e.g. <.. align="center"> Takes priority for this block but not inherited
15915 if (isset($this->blk[$this->blklvl]['block-align']) && $this->blk[$this->blklvl]['block-align']) {
15916 $align = $this->blk[$this->blklvl]['block-align'];
15917 }
15918 if (isset($this->blk[$this->blklvl]['direction'])) {
15919 $blockdir = $this->blk[$this->blklvl]['direction'];
15920 } else {
15921 $blockdir = "";
15922 }
15923 $this->divwidth = $this->blk[$this->blklvl]['width'];
15924 } else {
15925 $align = $this->cellTextAlign;
15926 $blockdir = $cell_dir;
15927 }
15928 $oldpage = $this->page;
15929
15930 // ADDED for Out of Block now done as Flowing Block
15931 if ($this->divwidth == 0) {
15932 $this->divwidth = $this->pgwidth;
15933 }
15934
15935 if (!$is_table) {
15936 $this->SetLineHeight($this->FontSizePt, $this->blk[$this->blklvl]['line_height']);
15937 }
15938 $this->divheight = $this->lineheight;
15939 $old_height = $this->divheight;
15940
15941 // As a failsafe - if font has been set but not output to page
15942 if (!$table_draft) {
15943 $this->SetFont($this->default_font, '', $this->default_font_size, true, true); // force output to page
15944 }
15945
15946 $this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, true, $blockdir, $table_draft);
15947
15948 $array_size = count($arrayaux);
15949
15950 // Added - Otherwise <div><div><p> did not output top margins/padding for 1st/2nd div
15951 if ($array_size == 0) {
15952 $this->finishFlowingBlock(true);
15953 } // true = END of flowing block
15954 // mPDF 6
15955 // ALL the chunks of textbuffer need to have at least basic OTLdata set
15956 // First make sure each element/chunk has the OTLdata for Bidi set.
15957 for ($i = 0; $i < $array_size; $i++) {
15958 if (empty($arrayaux[$i][18])) {
15959 if (substr($arrayaux[$i][0], 0, 3) == "\xbb\xa4\xac") { // object identifier has been identified!
15960 $unicode = [0xFFFC]; // Object replacement character
15961 } else {
15962 $unicode = $this->UTF8StringToArray($arrayaux[$i][0], false);
15963 }
15964 $is_strong = false;
15965 $this->getBasicOTLdata($arrayaux[$i][18], $unicode, $is_strong);
15966 }
15967 // Gets messed up if try and use core fonts inside a paragraph of text which needs to be BiDi re-ordered or OTLdata set
15968 if (($blockdir == 'rtl' || $this->biDirectional) && isset($arrayaux[$i][4]) && in_array($arrayaux[$i][4], ['ccourier', 'ctimes', 'chelvetica', 'csymbol', 'czapfdingbats'])) {
15969 throw new \Mpdf\MpdfException("You cannot use core fonts in a document which contains RTL text.");
15970 }
15971 }
15972 // mPDF 6
15973 // Process bidirectional text ready for bidi-re-ordering (which is done after line-breaks are established in WriteFlowingBlock etc.)
15974 if (($blockdir == 'rtl' || $this->biDirectional) && !$table_draft) {
15975 if (empty($this->otl)) {
15976 $this->otl = new Otl($this, $this->fontCache);
15977 }
15978 $this->otl->bidiPrepare($arrayaux, $blockdir);
15979 $array_size = count($arrayaux);
15980 }
15981
15982
15983 // Remove empty items // mPDF 6
15984 for ($i = $array_size - 1; $i > 0; $i--) {
15985 if (empty($arrayaux[$i][0]) && (isset($arrayaux[$i][16]) && $arrayaux[$i][16] !== '0') && empty($arrayaux[$i][7])) {
15986 unset($arrayaux[$i]);
15987 }
15988 }
15989
15990 // Correct adjoining borders for inline elements
15991 if (isset($arrayaux[0][16])) {
15992 $lastspanborder = $arrayaux[0][16];
15993 } else {
15994 $lastspanborder = false;
15995 }
15996 for ($i = 1; $i < $array_size; $i++) {
15997 if (isset($arrayaux[$i][16]) && $arrayaux[$i][16] == $lastspanborder &&
15998 ((!isset($arrayaux[$i][9]['bord-decoration']) && !isset($arrayaux[$i - 1][9]['bord-decoration'])) ||
15999 (isset($arrayaux[$i][9]['bord-decoration']) && isset($arrayaux[$i - 1][9]['bord-decoration']) && $arrayaux[$i][9]['bord-decoration'] == $arrayaux[$i - 1][9]['bord-decoration'])
16000 )
16001 ) {
16002 if (isset($arrayaux[$i][16]['R'])) {
16003 $lastspanborder = $arrayaux[$i][16];
16004 } else {
16005 $lastspanborder = false;
16006 }
16007 $arrayaux[$i][16]['L']['s'] = 0;
16008 $arrayaux[$i][16]['L']['w'] = 0;
16009 $arrayaux[$i - 1][16]['R']['s'] = 0;
16010 $arrayaux[$i - 1][16]['R']['w'] = 0;
16011 } else {
16012 if (isset($arrayaux[$i][16]['R'])) {
16013 $lastspanborder = $arrayaux[$i][16];
16014 } else {
16015 $lastspanborder = false;
16016 }
16017 }
16018 }
16019
16020 for ($i = 0; $i < $array_size; $i++) {
16021 // COLS
16022 $oldcolumn = $this->CurrCol;
16023 $vetor = isset($arrayaux[$i]) ? $arrayaux[$i] : null;
16024 if ($i == 0 && $vetor[0] != "\n" && ! $this->ispre) {
16025 $vetor[0] = ltrim($vetor[0]);
16026 if (!empty($vetor[18])) {
16027 $this->otl->trimOTLdata($vetor[18], true, false);
16028 } // *OTL*
16029 }
16030
16031 // FIXED TO ALLOW IT TO SHOW '0'
16032 if (empty($vetor[0]) && !($vetor[0] === '0') && empty($vetor[7])) { // Ignore empty text and not carrying an internal link
16033 // Check if it is the last element. If so then finish printing the block
16034 if ($i == ($array_size - 1)) {
16035 $this->finishFlowingBlock(true);
16036 } // true = END of flowing block
16037 continue;
16038 }
16039
16040
16041 // Activating buffer properties
16042 if (isset($vetor[11]) && $vetor[11] != '') { // Font Size
16043 if ($is_table && $this->shrin_k) {
16044 $this->SetFontSize($vetor[11] / $this->shrin_k, false);
16045 } else {
16046 $this->SetFontSize($vetor[11], false);
16047 }
16048 }
16049
16050 if (isset($vetor[17]) && !empty($vetor[17])) { // TextShadow
16051 $this->textshadow = $vetor[17];
16052 }
16053 if (isset($vetor[16]) && !empty($vetor[16])) { // Border
16054 $this->spanborddet = $vetor[16];
16055 $this->spanborder = true;
16056 }
16057
16058 if (isset($vetor[15])) { // Word spacing
16059 $this->wSpacingCSS = $vetor[15];
16060 if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
16061 $this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
16062 }
16063 }
16064 if (isset($vetor[14])) { // Letter spacing
16065 $this->lSpacingCSS = $vetor[14];
16066 if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
16067 $this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
16068 }
16069 }
16070
16071
16072 if (isset($vetor[10]) and ! empty($vetor[10])) { // Background color
16073 $this->spanbgcolorarray = $vetor[10];
16074 $this->spanbgcolor = true;
16075 }
16076 if (isset($vetor[9]) and ! empty($vetor[9])) { // Text parameters - Outline + hyphens
16077 $this->textparam = $vetor[9];
16078 $this->SetTextOutline($this->textparam);
16079 // mPDF 5.7.3 inline text-decoration parameters
16080 if ($is_table && $this->shrin_k) {
16081 if (isset($this->textparam['text-baseline'])) {
16082 $this->textparam['text-baseline'] /= $this->shrin_k;
16083 }
16084 if (isset($this->textparam['decoration-baseline'])) {
16085 $this->textparam['decoration-baseline'] /= $this->shrin_k;
16086 }
16087 if (isset($this->textparam['decoration-fontsize'])) {
16088 $this->textparam['decoration-fontsize'] /= $this->shrin_k;
16089 }
16090 }
16091 }
16092 if (isset($vetor[8])) { // mPDF 5.7.1
16093 $this->textvar = $vetor[8];
16094 }
16095 if (isset($vetor[7]) and $vetor[7] != '') { // internal target: <a name="anyvalue">
16096 $ily = $this->y;
16097 if ($this->table_rotate) {
16098 $this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page, "tbrot" => true];
16099 } elseif ($this->kwt) {
16100 $this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page, "kwt" => true];
16101 } elseif ($this->ColActive) {
16102 $this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page, "col" => $this->CurrCol];
16103 } elseif (!$this->keep_block_together) {
16104 $this->internallink[$vetor[7]] = ["Y" => $ily, "PAGE" => $this->page];
16105 }
16106 if (empty($vetor[0])) { // Ignore empty text
16107 // Check if it is the last element. If so then finish printing the block
16108 if ($i == ($array_size - 1)) {
16109 $this->finishFlowingBlock(true);
16110 } // true = END of flowing block
16111 continue;
16112 }
16113 }
16114 if (isset($vetor[5]) and $vetor[5] != '') { // Language // mPDF 6
16115 $this->currentLang = $vetor[5];
16116 }
16117 if (isset($vetor[4]) and $vetor[4] != '') { // Font Family
16118 $font = $this->SetFont($vetor[4], $this->FontStyle, 0, false);
16119 }
16120 if (!empty($vetor[3])) { // Font Color
16121 $cor = $vetor[3];
16122 $this->SetTColor($cor);
16123 }
16124 if (isset($vetor[2]) and $vetor[2] != '') { // Bold,Italic styles
16125 $this->SetStyles($vetor[2]);
16126 }
16127
16128 if (isset($vetor[12]) and $vetor[12] != '') { // Requested Bold,Italic
16129 $this->ReqFontStyle = $vetor[12];
16130 }
16131 if (isset($vetor[1]) and $vetor[1] != '') { // LINK
16132 if (strpos($vetor[1], ".") === false && strpos($vetor[1], "@") !== 0) { // assuming every external link has a dot indicating extension (e.g: .html .txt .zip www.somewhere.com etc.)
16133 // Repeated reference to same anchor?
16134 while (array_key_exists($vetor[1], $this->internallink)) {
16135 $vetor[1] = "#" . $vetor[1];
16136 }
16137 $this->internallink[$vetor[1]] = $this->AddLink();
16138 $vetor[1] = $this->internallink[$vetor[1]];
16139 }
16140 $this->HREF = $vetor[1]; // HREF link style set here ******
16141 }
16142
16143 // SPECIAL CONTENT - IMAGES & FORM OBJECTS
16144 // Print-out special content
16145
16146 if (substr($vetor[0], 0, 3) == "\xbb\xa4\xac") { // identifier has been identified!
16147 $objattr = $this->_getObjAttr($vetor[0]);
16148
16149 /* -- TABLES -- */
16150 if ($objattr['type'] == 'nestedtable') {
16151 if ($objattr['nestedcontent']) {
16152 $level = $objattr['level'];
16153 $table = &$this->table[$level][$objattr['table']];
16154
16155 if ($table_draft) {
16156 $this->y += $this->table[($level + 1)][$objattr['nestedcontent']]['h']; // nested table height
16157 $this->finishFlowingBlock(false, 'nestedtable');
16158 } else {
16159 $cell = &$table['cells'][$objattr['row']][$objattr['col']];
16160 $this->finishFlowingBlock(false, 'nestedtable');
16161 $save_dw = $this->divwidth;
16162 $save_buffer = $this->cellBorderBuffer;
16163 $this->cellBorderBuffer = [];
16164 $ncx = $this->x;
16165 list($dummyx, $w) = $this->_tableGetWidth($table, $objattr['row'], $objattr['col']);
16166 $ntw = $this->table[($level + 1)][$objattr['nestedcontent']]['w']; // nested table width
16167 if (!$this->simpleTables) {
16168 if ($this->packTableData) {
16169 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cell['borderbin']);
16170 } else {
16171 $br = $cell['border_details']['R']['w'];
16172 $bl = $cell['border_details']['L']['w'];
16173 }
16174 if ($table['borders_separate']) {
16175 $innerw = $w - $bl - $br - $cell['padding']['L'] - $cell['padding']['R'] - $table['border_spacing_H'];
16176 } else {
16177 $innerw = $w - $bl / 2 - $br / 2 - $cell['padding']['L'] - $cell['padding']['R'];
16178 }
16179 } elseif ($this->simpleTables) {
16180 if ($table['borders_separate']) {
16181 $innerw = $w - $table['simple']['border_details']['L']['w'] - $table['simple']['border_details']['R']['w'] - $cell['padding']['L'] - $cell['padding']['R'] - $table['border_spacing_H'];
16182 } else {
16183 $innerw = $w - $table['simple']['border_details']['L']['w'] / 2 - $table['simple']['border_details']['R']['w'] / 2 - $cell['padding']['L'] - $cell['padding']['R'];
16184 }
16185 }
16186 if ($cell['a'] == 'C' || $this->table[($level + 1)][$objattr['nestedcontent']]['a'] == 'C') {
16187 $ncx += ($innerw - $ntw) / 2;
16188 } elseif ($cell['a'] == 'R' || $this->table[($level + 1)][$objattr['nestedcontent']]['a'] == 'R') {
16189 $ncx += $innerw - $ntw;
16190 }
16191 $this->x = $ncx;
16192
16193 $this->_tableWrite($this->table[($level + 1)][$objattr['nestedcontent']]);
16194 $this->cellBorderBuffer = $save_buffer;
16195 $this->x = $bak_x;
16196 $this->divwidth = $save_dw;
16197 }
16198
16199 $this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
16200 }
16201 } else {
16202 /* -- END TABLES -- */
16203 if ($is_table) { // *TABLES*
16204 $maxWidth = $this->divwidth; // *TABLES*
16205 } // *TABLES*
16206 else { // *TABLES*
16207 $maxWidth = $this->divwidth - ($this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_right'] + $this->blk[$this->blklvl]['border_right']['w']);
16208 } // *TABLES*
16209
16210 /* -- CSS-IMAGE-FLOAT -- */
16211 // If float (already) exists at this level
16212 if (isset($this->floatmargins['R']) && $this->y <= $this->floatmargins['R']['y1'] && $this->y >= $this->floatmargins['R']['y0']) {
16213 $maxWidth -= $this->floatmargins['R']['w'];
16214 }
16215 if (isset($this->floatmargins['L']) && $this->y <= $this->floatmargins['L']['y1'] && $this->y >= $this->floatmargins['L']['y0']) {
16216 $maxWidth -= $this->floatmargins['L']['w'];
16217 }
16218 /* -- END CSS-IMAGE-FLOAT -- */
16219
16220 list($skipln) = $this->inlineObject($objattr['type'], '', $this->y, $objattr, $this->lMargin, ($this->flowingBlockAttr['contentWidth'] / Mpdf::SCALE), $maxWidth, $this->flowingBlockAttr['height'], false, $is_table);
16221 // 1 -> New line needed because of width
16222 // -1 -> Will fit width on line but NEW PAGE REQUIRED because of height
16223 // -2 -> Will not fit on line therefore needs new line but thus NEW PAGE REQUIRED
16224 $iby = $this->y;
16225 $oldpage = $this->page;
16226 $oldcol = $this->CurrCol;
16227 if (($skipln == 1 || $skipln == -2) && !isset($objattr['float'])) {
16228 $this->finishFlowingBlock(false, $objattr['type']);
16229 $this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
16230 }
16231
16232 if (!$table_draft) {
16233 $thispage = $this->page;
16234 if ($this->CurrCol != $oldcol) {
16235 $changedcol = true;
16236 } else {
16237 $changedcol = false;
16238 }
16239
16240 // the previous lines can already have triggered page break or column change
16241 if (!$changedcol && $skipln < 0 && $this->AcceptPageBreak() && $thispage == $oldpage) {
16242 $this->AddPage($this->CurOrientation);
16243
16244 // Added to correct Images already set on line before page advanced
16245 // i.e. if second inline image on line is higher than first and forces new page
16246 if (count($this->objectbuffer)) {
16247 $yadj = $iby - $this->y;
16248 foreach ($this->objectbuffer as $ib => $val) {
16249 if ($this->objectbuffer[$ib]['OUTER-Y']) {
16250 $this->objectbuffer[$ib]['OUTER-Y'] -= $yadj;
16251 }
16252 if ($this->objectbuffer[$ib]['BORDER-Y']) {
16253 $this->objectbuffer[$ib]['BORDER-Y'] -= $yadj;
16254 }
16255 if ($this->objectbuffer[$ib]['INNER-Y']) {
16256 $this->objectbuffer[$ib]['INNER-Y'] -= $yadj;
16257 }
16258 }
16259 }
16260 }
16261
16262 // Added to correct for OddEven Margins
16263 if ($this->page != $oldpage) {
16264 if (($this->page - $oldpage) % 2 == 1) {
16265 $bak_x += $this->MarginCorrection;
16266 }
16267 $oldpage = $this->page;
16268 $y = $this->tMargin - $paint_ht_corr;
16269 $this->oldy = $this->tMargin - $paint_ht_corr;
16270 $old_height = 0;
16271 }
16272 $this->x = $bak_x;
16273 /* -- COLUMNS -- */
16274 // COLS
16275 // OR COLUMN CHANGE
16276 if ($this->CurrCol != $oldcolumn) {
16277 if ($this->directionality == 'rtl') { // *OTL*
16278 $bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
16279 } // *OTL*
16280 else { // *OTL*
16281 $bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
16282 } // *OTL*
16283 $this->x = $bak_x;
16284 $oldcolumn = $this->CurrCol;
16285 $y = $this->y0 - $paint_ht_corr;
16286 $this->oldy = $this->y0 - $paint_ht_corr;
16287 $old_height = 0;
16288 }
16289 /* -- END COLUMNS -- */
16290 }
16291
16292 /* -- CSS-IMAGE-FLOAT -- */
16293 if ($objattr['type'] == 'image' && isset($objattr['float'])) {
16294 $fy = $this->y;
16295
16296 // DIV TOP MARGIN/BORDER/PADDING
16297 if ($this->flowingBlockAttr['newblock'] && ($this->flowingBlockAttr['blockstate'] == 1 || $this->flowingBlockAttr['blockstate'] == 3) && $this->flowingBlockAttr['lineCount'] == 0) {
16298 $fy += $this->blk[$this->blklvl]['margin_top'] + $this->blk[$this->blklvl]['padding_top'] + $this->blk[$this->blklvl]['border_top']['w'];
16299 }
16300
16301 if ($objattr['float'] == 'R') {
16302 $fx = $this->w - $this->rMargin - $objattr['width'] - ($this->blk[$this->blklvl]['outer_right_margin'] + $this->blk[$this->blklvl]['border_right']['w'] + $this->blk[$this->blklvl]['padding_right']);
16303 } elseif ($objattr['float'] == 'L') {
16304 $fx = $this->lMargin + ($this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_left']);
16305 }
16306 $w = $objattr['width'];
16307 $h = abs($objattr['height']);
16308
16309 $widthLeft = $maxWidth - ($this->flowingBlockAttr['contentWidth'] / Mpdf::SCALE);
16310 $maxHeight = $this->h - ($this->tMargin + $this->margin_header + $this->bMargin + 10);
16311 // For Images
16312 $extraWidth = ($objattr['border_left']['w'] + $objattr['border_right']['w'] + $objattr['margin_left'] + $objattr['margin_right']);
16313 $extraHeight = ($objattr['border_top']['w'] + $objattr['border_bottom']['w'] + $objattr['margin_top'] + $objattr['margin_bottom']);
16314
16315 if ($objattr['itype'] == 'wmf' || $objattr['itype'] == 'svg') {
16316 $file = $objattr['file'];
16317 $info = $this->formobjects[$file];
16318 } else {
16319 $file = $objattr['file'];
16320 $info = $this->images[$file];
16321 }
16322 $img_w = $w - $extraWidth;
16323 $img_h = $h - $extraHeight;
16324 if ($objattr['border_left']['w']) {
16325 $objattr['BORDER-WIDTH'] = $img_w + (($objattr['border_left']['w'] + $objattr['border_right']['w']) / 2);
16326 $objattr['BORDER-HEIGHT'] = $img_h + (($objattr['border_top']['w'] + $objattr['border_bottom']['w']) / 2);
16327 $objattr['BORDER-X'] = $fx + $objattr['margin_left'] + (($objattr['border_left']['w']) / 2);
16328 $objattr['BORDER-Y'] = $fy + $objattr['margin_top'] + (($objattr['border_top']['w']) / 2);
16329 }
16330 $objattr['INNER-WIDTH'] = $img_w;
16331 $objattr['INNER-HEIGHT'] = $img_h;
16332 $objattr['INNER-X'] = $fx + $objattr['margin_left'] + ($objattr['border_left']['w']);
16333 $objattr['INNER-Y'] = $fy + $objattr['margin_top'] + ($objattr['border_top']['w']);
16334 $objattr['ID'] = $info['i'];
16335 $objattr['OUTER-WIDTH'] = $w;
16336 $objattr['OUTER-HEIGHT'] = $h;
16337 $objattr['OUTER-X'] = $fx;
16338 $objattr['OUTER-Y'] = $fy;
16339 if ($objattr['float'] == 'R') {
16340 // If R float already exists at this level
16341 $this->floatmargins['R']['skipline'] = false;
16342 if (isset($this->floatmargins['R']['y1']) && $this->floatmargins['R']['y1'] > 0 && $fy < $this->floatmargins['R']['y1']) {
16343 $this->WriteFlowingBlock($vetor[0], $vetor[18]); // mPDF 5.7.1
16344 } // If L float already exists at this level
16345 elseif (isset($this->floatmargins['L']['y1']) && $this->floatmargins['L']['y1'] > 0 && $fy < $this->floatmargins['L']['y1']) {
16346 // Final check distance between floats is not now too narrow to fit text
16347 $mw = 2 * $this->GetCharWidth('W', false);
16348 if (($this->blk[$this->blklvl]['inner_width'] - $w - $this->floatmargins['L']['w']) < $mw) {
16349 $this->WriteFlowingBlock($vetor[0], $vetor[18]); // mPDF 5.7.1
16350 } else {
16351 $this->floatmargins['R']['x'] = $fx;
16352 $this->floatmargins['R']['w'] = $w;
16353 $this->floatmargins['R']['y0'] = $fy;
16354 $this->floatmargins['R']['y1'] = $fy + $h;
16355 if ($skipln == 1) {
16356 $this->floatmargins['R']['skipline'] = true;
16357 $this->floatmargins['R']['id'] = count($this->floatbuffer) + 0;
16358 $objattr['skipline'] = true;
16359 }
16360 $this->floatbuffer[] = $objattr;
16361 }
16362 } else {
16363 $this->floatmargins['R']['x'] = $fx;
16364 $this->floatmargins['R']['w'] = $w;
16365 $this->floatmargins['R']['y0'] = $fy;
16366 $this->floatmargins['R']['y1'] = $fy + $h;
16367 if ($skipln == 1) {
16368 $this->floatmargins['R']['skipline'] = true;
16369 $this->floatmargins['R']['id'] = count($this->floatbuffer) + 0;
16370 $objattr['skipline'] = true;
16371 }
16372 $this->floatbuffer[] = $objattr;
16373 }
16374 } elseif ($objattr['float'] == 'L') {
16375 // If L float already exists at this level
16376 $this->floatmargins['L']['skipline'] = false;
16377 if (isset($this->floatmargins['L']['y1']) && $this->floatmargins['L']['y1'] > 0 && $fy < $this->floatmargins['L']['y1']) {
16378 $this->floatmargins['L']['skipline'] = false;
16379 $this->WriteFlowingBlock($vetor[0], $vetor[18]); // mPDF 5.7.1
16380 } // If R float already exists at this level
16381 elseif (isset($this->floatmargins['R']['y1']) && $this->floatmargins['R']['y1'] > 0 && $fy < $this->floatmargins['R']['y1']) {
16382 // Final check distance between floats is not now too narrow to fit text
16383 $mw = 2 * $this->GetCharWidth('W', false);
16384 if (($this->blk[$this->blklvl]['inner_width'] - $w - $this->floatmargins['R']['w']) < $mw) {
16385 $this->WriteFlowingBlock($vetor[0], $vetor[18]); // mPDF 5.7.1
16386 } else {
16387 $this->floatmargins['L']['x'] = $fx + $w;
16388 $this->floatmargins['L']['w'] = $w;
16389 $this->floatmargins['L']['y0'] = $fy;
16390 $this->floatmargins['L']['y1'] = $fy + $h;
16391 if ($skipln == 1) {
16392 $this->floatmargins['L']['skipline'] = true;
16393 $this->floatmargins['L']['id'] = count($this->floatbuffer) + 0;
16394 $objattr['skipline'] = true;
16395 }
16396 $this->floatbuffer[] = $objattr;
16397 }
16398 } else {
16399 $this->floatmargins['L']['x'] = $fx + $w;
16400 $this->floatmargins['L']['w'] = $w;
16401 $this->floatmargins['L']['y0'] = $fy;
16402 $this->floatmargins['L']['y1'] = $fy + $h;
16403 if ($skipln == 1) {
16404 $this->floatmargins['L']['skipline'] = true;
16405 $this->floatmargins['L']['id'] = count($this->floatbuffer) + 0;
16406 $objattr['skipline'] = true;
16407 }
16408 $this->floatbuffer[] = $objattr;
16409 }
16410 }
16411 } else {
16412 /* -- END CSS-IMAGE-FLOAT -- */
16413 $this->WriteFlowingBlock($vetor[0], (isset($vetor[18]) ? $vetor[18] : null)); // mPDF 5.7.1
16414 /* -- CSS-IMAGE-FLOAT -- */
16415 }
16416 /* -- END CSS-IMAGE-FLOAT -- */
16417 } // *TABLES*
16418 } // END If special content
16419 else { // THE text
16420 if ($this->tableLevel) {
16421 $paint_ht_corr = 0;
16422 } // To move the y up when new column/page started if div border needed
16423 else {
16424 $paint_ht_corr = $this->blk[$this->blklvl]['border_top']['w'];
16425 }
16426
16427 if ($vetor[0] == "\n") { // We are reading a <BR> now turned into newline ("\n")
16428 if ($this->flowingBlockAttr['content']) {
16429 $this->finishFlowingBlock(false, 'br');
16430 } elseif ($is_table) {
16431 $this->y+= $this->_computeLineheight($this->cellLineHeight);
16432 } elseif (!$is_table) {
16433 $this->DivLn($this->lineheight);
16434 if ($this->ColActive) {
16435 $this->breakpoints[$this->CurrCol][] = $this->y;
16436 } // *COLUMNS*
16437 }
16438 // Added to correct for OddEven Margins
16439 if ($this->page != $oldpage) {
16440 if (($this->page - $oldpage) % 2 == 1) {
16441 $bak_x += $this->MarginCorrection;
16442 }
16443 $oldpage = $this->page;
16444 $y = $this->tMargin - $paint_ht_corr;
16445 $this->oldy = $this->tMargin - $paint_ht_corr;
16446 $old_height = 0;
16447 }
16448 $this->x = $bak_x;
16449 /* -- COLUMNS -- */
16450 // COLS
16451 // OR COLUMN CHANGE
16452 if ($this->CurrCol != $oldcolumn) {
16453 if ($this->directionality == 'rtl') { // *OTL*
16454 $bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
16455 } // *OTL*
16456 else { // *OTL*
16457 $bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
16458 } // *OTL*
16459 $this->x = $bak_x;
16460 $oldcolumn = $this->CurrCol;
16461 $y = $this->y0 - $paint_ht_corr;
16462 $this->oldy = $this->y0 - $paint_ht_corr;
16463 $old_height = 0;
16464 }
16465 /* -- END COLUMNS -- */
16466 $this->newFlowingBlock($this->divwidth, $this->divheight, $align, $is_table, $blockstate, false, $blockdir, $table_draft);
16467 } else {
16468 $this->WriteFlowingBlock($vetor[0], $vetor[18]); // mPDF 5.7.1
16469 // Added to correct for OddEven Margins
16470 if ($this->page != $oldpage) {
16471 if (($this->page - $oldpage) % 2 == 1) {
16472 $bak_x += $this->MarginCorrection;
16473 $this->x = $bak_x;
16474 }
16475 $oldpage = $this->page;
16476 $y = $this->tMargin - $paint_ht_corr;
16477 $this->oldy = $this->tMargin - $paint_ht_corr;
16478 $old_height = 0;
16479 }
16480 /* -- COLUMNS -- */
16481 // COLS
16482 // OR COLUMN CHANGE
16483 if ($this->CurrCol != $oldcolumn) {
16484 if ($this->directionality == 'rtl') { // *OTL*
16485 $bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
16486 } // *OTL*
16487 else { // *OTL*
16488 $bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
16489 } // *OTL*
16490 $this->x = $bak_x;
16491 $oldcolumn = $this->CurrCol;
16492 $y = $this->y0 - $paint_ht_corr;
16493 $this->oldy = $this->y0 - $paint_ht_corr;
16494 $old_height = 0;
16495 }
16496 /* -- END COLUMNS -- */
16497 }
16498 }
16499
16500 // Check if it is the last element. If so then finish printing the block
16501 if ($i == ($array_size - 1)) {
16502 $this->finishFlowingBlock(true); // true = END of flowing block
16503 // Added to correct for OddEven Margins
16504 if ($this->page != $oldpage) {
16505 if (($this->page - $oldpage) % 2 == 1) {
16506 $bak_x += $this->MarginCorrection;
16507 $this->x = $bak_x;
16508 }
16509 $oldpage = $this->page;
16510 $y = $this->tMargin - $paint_ht_corr;
16511 $this->oldy = $this->tMargin - $paint_ht_corr;
16512 $old_height = 0;
16513 }
16514
16515 /* -- COLUMNS -- */
16516 // COLS
16517 // OR COLUMN CHANGE
16518 if ($this->CurrCol != $oldcolumn) {
16519 if ($this->directionality == 'rtl') { // *OTL*
16520 $bak_x -= ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap); // *OTL*
16521 } // *OTL*
16522 else { // *OTL*
16523 $bak_x += ($this->CurrCol - $oldcolumn) * ($this->ColWidth + $this->ColGap);
16524 } // *OTL*
16525 $this->x = $bak_x;
16526 $oldcolumn = $this->CurrCol;
16527 $y = $this->y0 - $paint_ht_corr;
16528 $this->oldy = $this->y0 - $paint_ht_corr;
16529 $old_height = 0;
16530 }
16531 /* -- END COLUMNS -- */
16532 }
16533
16534 // RESETTING VALUES
16535 $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
16536 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
16537 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
16538 $this->colorarray = '';
16539 $this->spanbgcolorarray = '';
16540 $this->spanbgcolor = false;
16541 $this->spanborder = false;
16542 $this->spanborddet = [];
16543 $this->HREF = '';
16544 $this->textparam = [];
16545 $this->SetTextOutline();
16546
16547 $this->textvar = 0x00; // mPDF 5.7.1
16548 $this->OTLtags = [];
16549 $this->textshadow = '';
16550
16551 $this->currentfontfamily = '';
16552 $this->currentfontsize = '';
16553 $this->currentfontstyle = '';
16554 $this->currentLang = $this->default_lang; // mPDF 6
16555 $this->RestrictUnicodeFonts($this->default_available_fonts); // mPDF 6
16556 /* -- TABLES -- */
16557 if ($this->tableLevel) {
16558 $this->SetLineHeight('', $this->table[1][1]['cellLineHeight']); // *TABLES*
16559 } else { /* -- END TABLES -- */
16560 if (isset($this->blk[$this->blklvl]['line_height']) && $this->blk[$this->blklvl]['line_height']) {
16561 $this->SetLineHeight('', $this->blk[$this->blklvl]['line_height']); // sets default line height
16562 }
16563 }
16564 $this->ResetStyles();
16565 $this->lSpacingCSS = '';
16566 $this->wSpacingCSS = '';
16567 $this->fixedlSpacing = false;
16568 $this->minwSpacing = 0;
16569 $this->SetDash();
16570 $this->dash_on = false;
16571 $this->dotted_on = false;
16572 }//end of for(i=0;i<arraysize;i++)
16573
16574 $this->Reset(); // mPDF 6
16575 // PAINT DIV BORDER // DISABLED IN COLUMNS AS DOESN'T WORK WHEN BROKEN ACROSS COLS??
16576 if ((isset($this->blk[$this->blklvl]['border']) || isset($this->blk[$this->blklvl]['bgcolor']) || isset($this->blk[$this->blklvl]['box_shadow'])) && $blockstate && ($this->y != $this->oldy)) {
16577 $bottom_y = $this->y; // Does not include Bottom Margin
16578 if (isset($this->blk[$this->blklvl]['startpage']) && $this->blk[$this->blklvl]['startpage'] != $this->page && $blockstate != 1) {
16579 $this->PaintDivBB('pagetop', $blockstate);
16580 } elseif ($blockstate != 1) {
16581 $this->PaintDivBB('', $blockstate);
16582 }
16583 $this->y = $bottom_y;
16584 $this->x = $bak_x;
16585 }
16586
16587 // Reset Font
16588 $this->SetFontSize($this->default_font_size, false);
16589 if ($table_draft) {
16590 $ch = $this->y - $bak_y;
16591 $this->y = $bak_y;
16592 $this->x = $bak_x;
16593 return $ch;
16594 }
16595 }
16596
16597 function _setDashBorder($style, $div, $cp, $side)
16598 {
16599 if ($style == 'dashed' && (($side == 'L' || $side == 'R') || ($side == 'T' && $div != 'pagetop' && !$cp) || ($side == 'B' && $div != 'pagebottom') )) {
16600 $dashsize = 2; // final dash will be this + 1*linewidth
16601 $dashsizek = 1.5; // ratio of Dash/Blank
16602 $this->SetDash($dashsize, ($dashsize / $dashsizek) + ($this->LineWidth * 2));
16603 } elseif ($style == 'dotted' || ($side == 'T' && ($div == 'pagetop' || $cp)) || ($side == 'B' && $div == 'pagebottom')) {
16604 // Round join and cap
16605 $this->SetLineJoin(1);
16606 $this->SetLineCap(1);
16607 $this->SetDash(0.001, ($this->LineWidth * 3));
16608 }
16609 }
16610
16611 function _setBorderLine($b, $k = 1)
16612 {
16613 $this->SetLineWidth($b['w'] / $k);
16614 $this->SetDColor($b['c']);
16615 if ($b['c'][0] == 5) { // RGBa
16616 $this->SetAlpha(ord($b['c'][4]) / 100, 'Normal', false, 'S'); // mPDF 5.7.2
16617 } elseif ($b['c'][0] == 6) { // CMYKa
16618 $this->SetAlpha(ord($b['c'][5]) / 100, 'Normal', false, 'S'); // mPDF 5.7.2
16619 }
16620 }
16621
16622 function PaintDivBB($divider = '', $blockstate = 0, $blvl = 0)
16623 {
16624 // Borders & backgrounds are done elsewhere for columns - messes up the repositioning in printcolumnbuffer
16625 if ($this->ColActive) {
16626 return;
16627 } // *COLUMNS*
16628 if ($this->keep_block_together) {
16629 return;
16630 } // mPDF 6
16631 $save_y = $this->y;
16632 if (!$blvl) {
16633 $blvl = $this->blklvl;
16634 }
16635 $x0 = $x1 = $y0 = $y1 = 0;
16636
16637 // Added mPDF 3.0 Float DIV
16638 if (isset($this->blk[$blvl]['bb_painted'][$this->page]) && $this->blk[$blvl]['bb_painted'][$this->page]) {
16639 return;
16640 } // *CSS-FLOAT*
16641
16642 if (isset($this->blk[$blvl]['x0'])) {
16643 $x0 = $this->blk[$blvl]['x0'];
16644 } // left
16645 if (isset($this->blk[$blvl]['y1'])) {
16646 $y1 = $this->blk[$blvl]['y1'];
16647 } // bottom
16648 // Added mPDF 3.0 Float DIV - ensures backgrounds/borders are drawn to bottom of page
16649 if ($y1 == 0) {
16650 if ($divider == 'pagebottom') {
16651 $y1 = $this->h - $this->bMargin;
16652 } else {
16653 $y1 = $this->y;
16654 }
16655 }
16656
16657 $continuingpage = (isset($this->blk[$blvl]['startpage']) && $this->blk[$blvl]['startpage'] != $this->page);
16658
16659 if (isset($this->blk[$blvl]['y0'])) {
16660 $y0 = $this->blk[$blvl]['y0'];
16661 }
16662 $h = $y1 - $y0;
16663 $w = $this->blk[$blvl]['width'];
16664 $x1 = $x0 + $w;
16665
16666 // Set border-widths as used here
16667 $border_top = $this->blk[$blvl]['border_top']['w'];
16668 $border_bottom = $this->blk[$blvl]['border_bottom']['w'];
16669 $border_left = $this->blk[$blvl]['border_left']['w'];
16670 $border_right = $this->blk[$blvl]['border_right']['w'];
16671 if (!$this->blk[$blvl]['border_top'] || $divider == 'pagetop' || $continuingpage) {
16672 $border_top = 0;
16673 }
16674 if (!$this->blk[$blvl]['border_bottom'] || $blockstate == 1 || $divider == 'pagebottom') {
16675 $border_bottom = 0;
16676 }
16677
16678 $brTL_H = 0;
16679 $brTL_V = 0;
16680 $brTR_H = 0;
16681 $brTR_V = 0;
16682 $brBL_H = 0;
16683 $brBL_V = 0;
16684 $brBR_H = 0;
16685 $brBR_V = 0;
16686
16687 $brset = false;
16688 /* -- BORDER-RADIUS -- */
16689 if (isset($this->blk[$blvl]['border_radius_TL_H'])) {
16690 $brTL_H = $this->blk[$blvl]['border_radius_TL_H'];
16691 $brset = true;
16692 }
16693 if (isset($this->blk[$blvl]['border_radius_TL_V'])) {
16694 $brTL_V = $this->blk[$blvl]['border_radius_TL_V'];
16695 $brset = true;
16696 }
16697 if (isset($this->blk[$blvl]['border_radius_TR_H'])) {
16698 $brTR_H = $this->blk[$blvl]['border_radius_TR_H'];
16699 $brset = true;
16700 }
16701 if (isset($this->blk[$blvl]['border_radius_TR_V'])) {
16702 $brTR_V = $this->blk[$blvl]['border_radius_TR_V'];
16703 $brset = true;
16704 }
16705 if (isset($this->blk[$blvl]['border_radius_BR_H'])) {
16706 $brBR_H = $this->blk[$blvl]['border_radius_BR_H'];
16707 $brset = true;
16708 }
16709 if (isset($this->blk[$blvl]['border_radius_BR_V'])) {
16710 $brBR_V = $this->blk[$blvl]['border_radius_BR_V'];
16711 $brset = true;
16712 }
16713 if (isset($this->blk[$blvl]['border_radius_BL_H'])) {
16714 $brBL_H = $this->blk[$blvl]['border_radius_BL_H'];
16715 $brset = true;
16716 }
16717 if (isset($this->blk[$blvl]['border_radius_BL_V'])) {
16718 $brBL_V = $this->blk[$blvl]['border_radius_BL_V'];
16719 $brset = true;
16720 }
16721
16722 if (!$this->blk[$blvl]['border_top'] || $divider == 'pagetop' || $continuingpage) {
16723 $brTL_H = 0;
16724 $brTL_V = 0;
16725 $brTR_H = 0;
16726 $brTR_V = 0;
16727 }
16728 if (!$this->blk[$blvl]['border_bottom'] || $blockstate == 1 || $divider == 'pagebottom') {
16729 $brBL_H = 0;
16730 $brBL_V = 0;
16731 $brBR_H = 0;
16732 $brBR_V = 0;
16733 }
16734
16735 // Disallow border-radius if it is smaller than the border width.
16736 if ($brTL_H < min($border_left, $border_top)) {
16737 $brTL_H = $brTL_V = 0;
16738 }
16739 if ($brTL_V < min($border_left, $border_top)) {
16740 $brTL_V = $brTL_H = 0;
16741 }
16742 if ($brTR_H < min($border_right, $border_top)) {
16743 $brTR_H = $brTR_V = 0;
16744 }
16745 if ($brTR_V < min($border_right, $border_top)) {
16746 $brTR_V = $brTR_H = 0;
16747 }
16748 if ($brBL_H < min($border_left, $border_bottom)) {
16749 $brBL_H = $brBL_V = 0;
16750 }
16751 if ($brBL_V < min($border_left, $border_bottom)) {
16752 $brBL_V = $brBL_H = 0;
16753 }
16754 if ($brBR_H < min($border_right, $border_bottom)) {
16755 $brBR_H = $brBR_V = 0;
16756 }
16757 if ($brBR_V < min($border_right, $border_bottom)) {
16758 $brBR_V = $brBR_H = 0;
16759 }
16760
16761 // CHECK FOR radii that sum to > width or height of div ********
16762 $f = min($h / ($brTL_V + $brBL_V + 0.001), $h / ($brTR_V + $brBR_V + 0.001), $w / ($brTL_H + $brTR_H + 0.001), $w / ($brBL_H + $brBR_H + 0.001));
16763 if ($f < 1) {
16764 $brTL_H *= $f;
16765 $brTL_V *= $f;
16766 $brTR_H *= $f;
16767 $brTR_V *= $f;
16768 $brBL_H *= $f;
16769 $brBL_V *= $f;
16770 $brBR_H *= $f;
16771 $brBR_V *= $f;
16772 }
16773 /* -- END BORDER-RADIUS -- */
16774
16775 $tbcol = $this->colorConverter->convert(255, $this->PDFAXwarnings);
16776 for ($l = 0; $l <= $blvl; $l++) {
16777 if ($this->blk[$l]['bgcolor']) {
16778 $tbcol = $this->blk[$l]['bgcolorarray'];
16779 }
16780 }
16781
16782 // BORDERS
16783 if (isset($this->blk[$blvl]['y0']) && $this->blk[$blvl]['y0']) {
16784 $y0 = $this->blk[$blvl]['y0'];
16785 }
16786 $h = $y1 - $y0;
16787 $w = $this->blk[$blvl]['width'];
16788
16789 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
16790 $tbd = $this->blk[$blvl]['border_top'];
16791
16792 $legend = '';
16793 $legbreakL = 0;
16794 $legbreakR = 0;
16795 // BORDER LEGEND
16796 if (isset($this->blk[$blvl]['border_legend']) && $this->blk[$blvl]['border_legend']) {
16797 $legend = $this->blk[$blvl]['border_legend']; // Same structure array as textbuffer
16798 $txt = $legend[0] = ltrim($legend[0]);
16799 if (!empty($legend[18])) {
16800 $this->otl->trimOTLdata($legend[18], true, false);
16801 } // *OTL*
16802 // Set font, size, style, color
16803 $this->SetFont($legend[4], $legend[2], $legend[11]);
16804 if (isset($legend[3]) && $legend[3]) {
16805 $cor = $legend[3];
16806 $this->SetTColor($cor);
16807 }
16808 $stringWidth = $this->GetStringWidth($txt, true, $legend[18], $legend[8]);
16809 $save_x = $this->x;
16810 $save_y = $this->y;
16811 $save_currentfontfamily = $this->FontFamily;
16812 $save_currentfontsize = $this->FontSizePt;
16813 $save_currentfontstyle = $this->FontStyle;
16814 $this->y = $y0 - $this->FontSize / 2 + $this->blk[$blvl]['border_top']['w'] / 2;
16815 $this->x = $x0 + $this->blk[$blvl]['padding_left'] + $this->blk[$blvl]['border_left']['w'];
16816
16817 // Set the distance from the border line to the text ? make configurable variable
16818 $gap = 0.2 * $this->FontSize;
16819 $legbreakL = $this->x - $gap;
16820 $legbreakR = $this->x + $stringWidth + $gap;
16821 $this->magic_reverse_dir($txt, $this->blk[$blvl]['direction'], $legend[18]);
16822 $fill = '';
16823 $this->Cell($stringWidth, $this->FontSize, $txt, '', 0, 'C', $fill, '', 0, 0, 0, 'M', $fill, false, $legend[18], $legend[8]);
16824 // Reset
16825 $this->x = $save_x;
16826 $this->y = $save_y;
16827 $this->SetFont($save_currentfontfamily, $save_currentfontstyle, $save_currentfontsize);
16828 $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
16829 }
16830
16831 if (isset($tbd['s']) && $tbd['s']) {
16832 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
16833 $this->writer->write('q');
16834 $this->SetLineWidth(0);
16835 $this->writer->write(sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
16836 $this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
16837 $this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
16838 $this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
16839 $this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
16840 }
16841
16842 $this->_setBorderLine($tbd);
16843 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
16844 $legbreakL -= $border_top / 2; // because line cap different
16845 $legbreakR += $border_top / 2;
16846 $this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'T');
16847 } /* -- BORDER-RADIUS -- */ elseif (($brTL_V && $brTL_H) || ($brTR_V && $brTR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16848 $this->SetLineJoin(0);
16849 $this->SetLineCap(0);
16850 }
16851 $s = '';
16852 if ($brTR_H && $brTR_V) {
16853 $s .= ($this->_EllipseArc($x0 + $w - $brTR_H, $y0 + $brTR_V, $brTR_H - $border_top / 2, $brTR_V - $border_top / 2, 1, 2, true)) . "\n";
16854 } else { /* -- END BORDER-RADIUS -- */
16855 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16856 $s .= (sprintf('%.3F %.3F m ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16857 } else {
16858 $s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_top / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16859 }
16860 }
16861 /* -- BORDER-RADIUS -- */
16862 if ($brTL_H && $brTL_V) {
16863 if ($legend) {
16864 if ($legbreakR < ($x0 + $w - $brTR_H)) {
16865 $s .= (sprintf('%.3F %.3F l ', $legbreakR * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16866 }
16867 if ($legbreakL > ($x0 + $brTL_H )) {
16868 $s .= (sprintf('%.3F %.3F m ', $legbreakL * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16869 $s .= (sprintf('%.3F %.3F l ', ($x0 + $brTL_H ) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE) . "\n");
16870 } else {
16871 $s .= (sprintf('%.3F %.3F m ', ($x0 + $brTL_H ) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16872 }
16873 } else {
16874 $s .= (sprintf('%.3F %.3F l ', ($x0 + $brTL_H ) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16875 }
16876 $s .= ($this->_EllipseArc($x0 + $brTL_H, $y0 + $brTL_V, $brTL_H - $border_top / 2, $brTL_V - $border_top / 2, 2, 1)) . "\n";
16877 } else {
16878 /* -- END BORDER-RADIUS -- */
16879 if ($legend) {
16880 if ($legbreakR < ($x0 + $w)) {
16881 $s .= (sprintf('%.3F %.3F l ', $legbreakR * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16882 }
16883 if ($legbreakL > ($x0)) {
16884 $s .= (sprintf('%.3F %.3F m ', $legbreakL * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16885 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16886 $s .= (sprintf('%.3F %.3F l ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16887 } else {
16888 $s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_top / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16889 }
16890 } elseif ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16891 $s .= (sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16892 } else {
16893 $s .= (sprintf('%.3F %.3F m ', ($x0 + $border_top / 2) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16894 }
16895 } elseif ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16896 $s .= (sprintf('%.3F %.3F l ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16897 } else {
16898 $s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_top / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_top / 2))) * Mpdf::SCALE)) . "\n";
16899 }
16900 /* -- BORDER-RADIUS -- */
16901 }
16902 /* -- END BORDER-RADIUS -- */
16903 $s .= 'S' . "\n";
16904 $this->writer->write($s);
16905
16906 if ($tbd['style'] == 'double') {
16907 $this->SetLineWidth($tbd['w'] / 3);
16908 $this->SetDColor($tbcol);
16909 $this->writer->write($s);
16910 }
16911 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
16912 $this->writer->write('Q');
16913 }
16914
16915 // Reset Corners and Dash off
16916 $this->SetLineWidth(0.1);
16917 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
16918 $this->SetLineJoin(2);
16919 $this->SetLineCap(2);
16920 $this->SetDash();
16921 }
16922 }
16923 // Reinstate line above for dotted line divider when block border crosses a page
16924 // elseif ($divider == 'pagetop' || $continuingpage) {
16925
16926 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
16927 $tbd = $this->blk[$blvl]['border_bottom'];
16928 if (isset($tbd['s']) && $tbd['s']) {
16929 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
16930 $this->writer->write('q');
16931 $this->SetLineWidth(0);
16932 $this->writer->write(sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
16933 $this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
16934 $this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
16935 $this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
16936 $this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
16937 }
16938
16939 $this->_setBorderLine($tbd);
16940 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
16941 $this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'B');
16942 } /* -- BORDER-RADIUS -- */ elseif (($brBL_V && $brBL_H) || ($brBR_V && $brBR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16943 $this->SetLineJoin(0);
16944 $this->SetLineCap(0);
16945 }
16946 $s = '';
16947 if ($brBL_H && $brBL_V) {
16948 $s .= ($this->_EllipseArc($x0 + $brBL_H, $y0 + $h - $brBL_V, $brBL_H - $border_bottom / 2, $brBL_V - $border_bottom / 2, 3, 2, true)) . "\n";
16949 } else { /* -- END BORDER-RADIUS -- */
16950 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16951 $s .= (sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
16952 } else {
16953 $s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_bottom / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
16954 }
16955 }
16956 /* -- BORDER-RADIUS -- */
16957 if ($brBR_H && $brBR_V) {
16958 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_bottom / 2) - $brBR_H ) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
16959 $s .= ($this->_EllipseArc($x0 + $w - $brBR_H, $y0 + $h - $brBR_V, $brBR_H - $border_bottom / 2, $brBR_V - $border_bottom / 2, 4, 1)) . "\n";
16960 } else { /* -- END BORDER-RADIUS -- */
16961 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
16962 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
16963 } else {
16964 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_bottom / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_bottom / 2))) * Mpdf::SCALE)) . "\n";
16965 }
16966 }
16967 $s .= 'S' . "\n";
16968 $this->writer->write($s);
16969
16970 if ($tbd['style'] == 'double') {
16971 $this->SetLineWidth($tbd['w'] / 3);
16972 $this->SetDColor($tbcol);
16973 $this->writer->write($s);
16974 }
16975 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
16976 $this->writer->write('Q');
16977 }
16978
16979 // Reset Corners and Dash off
16980 $this->SetLineWidth(0.1);
16981 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
16982 $this->SetLineJoin(2);
16983 $this->SetLineCap(2);
16984 $this->SetDash();
16985 }
16986 }
16987 // Reinstate line below for dotted line divider when block border crosses a page
16988 // elseif ($blockstate == 1 || $divider == 'pagebottom') {
16989
16990 if ($this->blk[$blvl]['border_left']) {
16991 $tbd = $this->blk[$blvl]['border_left'];
16992 if (isset($tbd['s']) && $tbd['s']) {
16993 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
16994 $this->writer->write('q');
16995 $this->SetLineWidth(0);
16996 $this->writer->write(sprintf('%.3F %.3F m ', ($x0) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
16997 $this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
16998 $this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $border_left) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
16999 $this->writer->write(sprintf('%.3F %.3F l ', ($x0) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
17000 $this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
17001 }
17002
17003 $this->_setBorderLine($tbd);
17004 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17005 $this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'L');
17006 } /* -- BORDER-RADIUS -- */ elseif (($brTL_V && $brTL_H) || ($brBL_V && $brBL_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17007 $this->SetLineJoin(0);
17008 $this->SetLineCap(0);
17009 }
17010 $s = '';
17011 if ($brTL_V && $brTL_H) {
17012 $s .= ($this->_EllipseArc($x0 + $brTL_H, $y0 + $brTL_V, $brTL_H - $border_left / 2, $brTL_V - $border_left / 2, 2, 2, true)) . "\n";
17013 } else { /* -- END BORDER-RADIUS -- */
17014 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17015 $s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE)) . "\n";
17016 } else {
17017 $s .= (sprintf('%.3F %.3F m ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_left / 2))) * Mpdf::SCALE)) . "\n";
17018 }
17019 }
17020 /* -- BORDER-RADIUS -- */
17021 if ($brBL_V && $brBL_H) {
17022 $s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_left / 2) - $brBL_V) ) * Mpdf::SCALE)) . "\n";
17023 $s .= ($this->_EllipseArc($x0 + $brBL_H, $y0 + $h - $brBL_V, $brBL_H - $border_left / 2, $brBL_V - $border_left / 2, 3, 1)) . "\n";
17024 } else { /* -- END BORDER-RADIUS -- */
17025 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17026 $s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h) ) * Mpdf::SCALE)) . "\n";
17027 } else {
17028 $s .= (sprintf('%.3F %.3F l ', ($x0 + ($border_left / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_left / 2)) ) * Mpdf::SCALE)) . "\n";
17029 }
17030 }
17031 $s .= 'S' . "\n";
17032 $this->writer->write($s);
17033
17034 if ($tbd['style'] == 'double') {
17035 $this->SetLineWidth($tbd['w'] / 3);
17036 $this->SetDColor($tbcol);
17037 $this->writer->write($s);
17038 }
17039 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
17040 $this->writer->write('Q');
17041 }
17042
17043 // Reset Corners and Dash off
17044 $this->SetLineWidth(0.1);
17045 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
17046 $this->SetLineJoin(2);
17047 $this->SetLineCap(2);
17048 $this->SetDash();
17049 }
17050 }
17051 if ($this->blk[$blvl]['border_right']) {
17052 $tbd = $this->blk[$blvl]['border_right'];
17053 if (isset($tbd['s']) && $tbd['s']) {
17054 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
17055 $this->writer->write('q');
17056 $this->SetLineWidth(0);
17057 $this->writer->write(sprintf('%.3F %.3F m ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0)) * Mpdf::SCALE));
17058 $this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $border_top)) * Mpdf::SCALE));
17059 $this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w - $border_right) * Mpdf::SCALE, ($this->h - ($y0 + $h - $border_bottom)) * Mpdf::SCALE));
17060 $this->writer->write(sprintf('%.3F %.3F l ', ($x0 + $w) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE));
17061 $this->writer->write(' h W n '); // Ends path no-op & Sets the clipping path
17062 }
17063
17064 $this->_setBorderLine($tbd);
17065 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17066 $this->_setDashBorder($tbd['style'], $divider, $continuingpage, 'R');
17067 } /* -- BORDER-RADIUS -- */ elseif (($brTR_V && $brTR_H) || ($brBR_V && $brBR_H) || $tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17068 $this->SetLineJoin(0);
17069 $this->SetLineCap(0);
17070 }
17071 $s = '';
17072 if ($brBR_V && $brBR_H) {
17073 $s .= ($this->_EllipseArc($x0 + $w - $brBR_H, $y0 + $h - $brBR_V, $brBR_H - $border_right / 2, $brBR_V - $border_right / 2, 4, 2, true)) . "\n";
17074 } else { /* -- END BORDER-RADIUS -- */
17075 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17076 $s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h)) * Mpdf::SCALE)) . "\n";
17077 } else {
17078 $s .= (sprintf('%.3F %.3F m ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + $h - ($border_right / 2))) * Mpdf::SCALE)) . "\n";
17079 }
17080 }
17081 /* -- BORDER-RADIUS -- */
17082 if ($brTR_V && $brTR_H) {
17083 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_right / 2) + $brTR_V) ) * Mpdf::SCALE)) . "\n";
17084 $s .= ($this->_EllipseArc($x0 + $w - $brTR_H, $y0 + $brTR_V, $brTR_H - $border_right / 2, $brTR_V - $border_right / 2, 1, 1)) . "\n";
17085 } else { /* -- END BORDER-RADIUS -- */
17086 if ($tbd['style'] == 'solid' || $tbd['style'] == 'double') {
17087 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0) ) * Mpdf::SCALE)) . "\n";
17088 } else {
17089 $s .= (sprintf('%.3F %.3F l ', ($x0 + $w - ($border_right / 2)) * Mpdf::SCALE, ($this->h - ($y0 + ($border_right / 2)) ) * Mpdf::SCALE)) . "\n";
17090 }
17091 }
17092 $s .= 'S' . "\n";
17093 $this->writer->write($s);
17094
17095 if ($tbd['style'] == 'double') {
17096 $this->SetLineWidth($tbd['w'] / 3);
17097 $this->SetDColor($tbcol);
17098 $this->writer->write($s);
17099 }
17100 if (!$brset && $tbd['style'] != 'dotted' && $tbd['style'] != 'dashed') {
17101 $this->writer->write('Q');
17102 }
17103
17104 // Reset Corners and Dash off
17105 $this->SetLineWidth(0.1);
17106 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
17107 $this->SetLineJoin(2);
17108 $this->SetLineCap(2);
17109 $this->SetDash();
17110 }
17111 }
17112
17113
17114 $this->SetDash();
17115 $this->y = $save_y;
17116
17117
17118 // BACKGROUNDS are disabled in columns/kbt/headers - messes up the repositioning in printcolumnbuffer
17119 if ($this->ColActive || $this->kwt || $this->keep_block_together) {
17120 return;
17121 }
17122
17123
17124 $bgx0 = $x0;
17125 $bgx1 = $x1;
17126 $bgy0 = $y0;
17127 $bgy1 = $y1;
17128
17129 // Defined br values represent the radius of the outer curve - need to take border-width/2 from each radius for drawing the borders
17130 if (isset($this->blk[$blvl]['background_clip']) && $this->blk[$blvl]['background_clip'] == 'padding-box') {
17131 $brbgTL_H = max(0, $brTL_H - $this->blk[$blvl]['border_left']['w']);
17132 $brbgTL_V = max(0, $brTL_V - $this->blk[$blvl]['border_top']['w']);
17133 $brbgTR_H = max(0, $brTR_H - $this->blk[$blvl]['border_right']['w']);
17134 $brbgTR_V = max(0, $brTR_V - $this->blk[$blvl]['border_top']['w']);
17135 $brbgBL_H = max(0, $brBL_H - $this->blk[$blvl]['border_left']['w']);
17136 $brbgBL_V = max(0, $brBL_V - $this->blk[$blvl]['border_bottom']['w']);
17137 $brbgBR_H = max(0, $brBR_H - $this->blk[$blvl]['border_right']['w']);
17138 $brbgBR_V = max(0, $brBR_V - $this->blk[$blvl]['border_bottom']['w']);
17139 $bgx0 += $this->blk[$blvl]['border_left']['w'];
17140 $bgx1 -= $this->blk[$blvl]['border_right']['w'];
17141 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
17142 $bgy0 += $this->blk[$blvl]['border_top']['w'];
17143 }
17144 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
17145 $bgy1 -= $this->blk[$blvl]['border_bottom']['w'];
17146 }
17147 } elseif (isset($this->blk[$blvl]['background_clip']) && $this->blk[$blvl]['background_clip'] == 'content-box') {
17148 $brbgTL_H = max(0, $brTL_H - $this->blk[$blvl]['border_left']['w'] - $this->blk[$blvl]['padding_left']);
17149 $brbgTL_V = max(0, $brTL_V - $this->blk[$blvl]['border_top']['w'] - $this->blk[$blvl]['padding_top']);
17150 $brbgTR_H = max(0, $brTR_H - $this->blk[$blvl]['border_right']['w'] - $this->blk[$blvl]['padding_right']);
17151 $brbgTR_V = max(0, $brTR_V - $this->blk[$blvl]['border_top']['w'] - $this->blk[$blvl]['padding_top']);
17152 $brbgBL_H = max(0, $brBL_H - $this->blk[$blvl]['border_left']['w'] - $this->blk[$blvl]['padding_left']);
17153 $brbgBL_V = max(0, $brBL_V - $this->blk[$blvl]['border_bottom']['w'] - $this->blk[$blvl]['padding_bottom']);
17154 $brbgBR_H = max(0, $brBR_H - $this->blk[$blvl]['border_right']['w'] - $this->blk[$blvl]['padding_right']);
17155 $brbgBR_V = max(0, $brBR_V - $this->blk[$blvl]['border_bottom']['w'] - $this->blk[$blvl]['padding_bottom']);
17156 $bgx0 += $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
17157 $bgx1 -= $this->blk[$blvl]['border_right']['w'] + $this->blk[$blvl]['padding_right'];
17158 if (($this->blk[$blvl]['border_top']['w'] || $this->blk[$blvl]['padding_top']) && $divider != 'pagetop' && !$continuingpage) {
17159 $bgy0 += $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
17160 }
17161 if (($this->blk[$blvl]['border_bottom']['w'] || $this->blk[$blvl]['padding_bottom']) && $blockstate != 1 && $divider != 'pagebottom') {
17162 $bgy1 -= $this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom'];
17163 }
17164 } else {
17165 $brbgTL_H = $brTL_H;
17166 $brbgTL_V = $brTL_V;
17167 $brbgTR_H = $brTR_H;
17168 $brbgTR_V = $brTR_V;
17169 $brbgBL_H = $brBL_H;
17170 $brbgBL_V = $brBL_V;
17171 $brbgBR_H = $brBR_H;
17172 $brbgBR_V = $brBR_V;
17173 }
17174
17175 // Set clipping path
17176 $s = ' q 0 w '; // Line width=0
17177 $s .= sprintf('%.3F %.3F m ', ($bgx0 + $brbgTL_H ) * Mpdf::SCALE, ($this->h - $bgy0) * Mpdf::SCALE); // start point TL before the arc
17178 /* -- BORDER-RADIUS -- */
17179 if ($brbgTL_H || $brbgTL_V) {
17180 $s .= $this->_EllipseArc($bgx0 + $brbgTL_H, $bgy0 + $brbgTL_V, $brbgTL_H, $brbgTL_V, 2); // segment 2 TL
17181 }
17182 /* -- END BORDER-RADIUS -- */
17183 $s .= sprintf('%.3F %.3F l ', ($bgx0) * Mpdf::SCALE, ($this->h - ($bgy1 - $brbgBL_V )) * Mpdf::SCALE); // line to BL
17184 /* -- BORDER-RADIUS -- */
17185 if ($brbgBL_H || $brbgBL_V) {
17186 $s .= $this->_EllipseArc($bgx0 + $brbgBL_H, $bgy1 - $brbgBL_V, $brbgBL_H, $brbgBL_V, 3); // segment 3 BL
17187 }
17188 /* -- END BORDER-RADIUS -- */
17189 $s .= sprintf('%.3F %.3F l ', ($bgx1 - $brbgBR_H ) * Mpdf::SCALE, ($this->h - ($bgy1)) * Mpdf::SCALE); // line to BR
17190 /* -- BORDER-RADIUS -- */
17191 if ($brbgBR_H || $brbgBR_V) {
17192 $s .= $this->_EllipseArc($bgx1 - $brbgBR_H, $bgy1 - $brbgBR_V, $brbgBR_H, $brbgBR_V, 4); // segment 4 BR
17193 }
17194 /* -- END BORDER-RADIUS -- */
17195 $s .= sprintf('%.3F %.3F l ', ($bgx1) * Mpdf::SCALE, ($this->h - ($bgy0 + $brbgTR_V)) * Mpdf::SCALE); // line to TR
17196 /* -- BORDER-RADIUS -- */
17197 if ($brbgTR_H || $brbgTR_V) {
17198 $s .= $this->_EllipseArc($bgx1 - $brbgTR_H, $bgy0 + $brbgTR_V, $brbgTR_H, $brbgTR_V, 1); // segment 1 TR
17199 }
17200 /* -- END BORDER-RADIUS -- */
17201 $s .= sprintf('%.3F %.3F l ', ($bgx0 + $brbgTL_H ) * Mpdf::SCALE, ($this->h - $bgy0) * Mpdf::SCALE); // line to TL
17202 // Box Shadow
17203 $shadow = '';
17204 if (isset($this->blk[$blvl]['box_shadow']) && $this->blk[$blvl]['box_shadow'] && $h > 0) {
17205 foreach ($this->blk[$blvl]['box_shadow'] as $sh) {
17206 // Colors
17207 if ($sh['col'][0] == 1) {
17208 $colspace = 'Gray';
17209 if ($sh['col'][2] == 1) {
17210 $col1 = '1' . $sh['col'][1] . '1' . $sh['col'][3];
17211 } else {
17212 $col1 = '1' . $sh['col'][1] . '1' . chr(100);
17213 }
17214 $col2 = '1' . $sh['col'][1] . '1' . chr(0);
17215 } elseif ($sh['col'][0] == 4) { // CMYK
17216 $colspace = 'CMYK';
17217 $col1 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(100);
17218 $col2 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(0);
17219 } elseif ($sh['col'][0] == 5) { // RGBa
17220 $colspace = 'RGB';
17221 $col1 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4];
17222 $col2 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(0);
17223 } elseif ($sh['col'][0] == 6) { // CMYKa
17224 $colspace = 'CMYK';
17225 $col1 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . $sh['col'][5];
17226 $col2 = '6' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . $sh['col'][4] . chr(0);
17227 } else {
17228 $colspace = 'RGB';
17229 $col1 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(100);
17230 $col2 = '5' . $sh['col'][1] . $sh['col'][2] . $sh['col'][3] . chr(0);
17231 }
17232
17233 // Use clipping path as set above (and rectangle around page) to clip area outside box
17234 $shadow .= $s; // Use the clipping path with W*
17235 $shadow .= sprintf('0 %.3F m %.3F %.3F l ', $this->h * Mpdf::SCALE, $this->w * Mpdf::SCALE, $this->h * Mpdf::SCALE);
17236 $shadow .= sprintf('%.3F 0 l 0 0 l 0 %.3F l ', $this->w * Mpdf::SCALE, $this->h * Mpdf::SCALE);
17237 $shadow .= 'W n' . "\n";
17238
17239 $sh['blur'] = abs($sh['blur']); // cannot have negative blur value
17240 // Ensure spread/blur do not make effective shadow width/height < 0
17241 // Could do more complex things but this just adjusts spread value
17242 if (-$sh['spread'] + $sh['blur'] / 2 > min($w / 2, $h / 2)) {
17243 $sh['spread'] = $sh['blur'] / 2 - min($w / 2, $h / 2) + 0.01;
17244 }
17245 // Shadow Offset
17246 if ($sh['x'] || $sh['y']) {
17247 $shadow .= sprintf(' q 1 0 0 1 %.4F %.4F cm', $sh['x'] * Mpdf::SCALE, -$sh['y'] * Mpdf::SCALE) . "\n";
17248 }
17249
17250 // Set path for INNER shadow
17251 $shadow .= ' q 0 w ';
17252 $shadow .= $this->SetFColor($col1, true) . "\n";
17253 if ($col1[0] == 5 && ord($col1[4]) < 100) { // RGBa
17254 $shadow .= $this->SetAlpha(ord($col1[4]) / 100, 'Normal', true, 'F') . "\n";
17255 } elseif ($col1[0] == 6 && ord($col1[5]) < 100) { // CMYKa
17256 $shadow .= $this->SetAlpha(ord($col1[5]) / 100, 'Normal', true, 'F') . "\n";
17257 } elseif ($col1[0] == 1 && $col1[2] == 1 && ord($col1[3]) < 100) { // Gray
17258 $shadow .= $this->SetAlpha(ord($col1[3]) / 100, 'Normal', true, 'F') . "\n";
17259 }
17260
17261 // Blur edges
17262 $mag = 0.551784; // Bezier Control magic number for 4-part spline for circle/ellipse
17263 $mag2 = 0.551784; // Bezier Control magic number to fill in edge of blurred rectangle
17264 $d1 = $sh['spread'] + $sh['blur'] / 2;
17265 $d2 = $sh['spread'] - $sh['blur'] / 2;
17266 $bl = $sh['blur'];
17267 $x00 = $x0 - $d1;
17268 $y00 = $y0 - $d1;
17269 $w00 = $w + $d1 * 2;
17270 $h00 = $h + $d1 * 2;
17271
17272 // If any border-radius is greater width-negative spread(inner edge), ignore radii for shadow or screws up
17273 $flatten = false;
17274 if (max($brbgTR_H, $brbgTL_H, $brbgBR_H, $brbgBL_H) >= $w + $d2) {
17275 $flatten = true;
17276 }
17277 if (max($brbgTR_V, $brbgTL_V, $brbgBR_V, $brbgBL_V) >= $h + $d2) {
17278 $flatten = true;
17279 }
17280
17281
17282 // TOP RIGHT corner
17283 $p1x = $x00 + $w00 - $d1 - $brbgTR_H;
17284 $p1c2x = $p1x + ($d2 + $brbgTR_H) * $mag;
17285 $p1y = $y00 + $bl;
17286 $p2x = $x00 + $w00 - $d1 - $brbgTR_H;
17287 $p2c2x = $p2x + ($d1 + $brbgTR_H) * $mag;
17288 $p2y = $y00;
17289 $p2c1y = $p2y + $bl / 2;
17290 $p3x = $x00 + $w00;
17291 $p3c2x = $p3x - $bl / 2;
17292 $p3y = $y00 + $d1 + $brbgTR_V;
17293 $p3c1y = $p3y - ($d1 + $brbgTR_V) * $mag;
17294 $p4x = $x00 + $w00 - $bl;
17295 $p4y = $y00 + $d1 + $brbgTR_V;
17296 $p4c2y = $p4y - ($d2 + $brbgTR_V) * $mag;
17297 if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
17298 $p1x = $x00 + $w00 - $bl;
17299 $p1c2x = $p1x;
17300 $p2x = $x00 + $w00 - $bl;
17301 $p2c2x = $p2x + $bl * $mag2;
17302 $p3y = $y00 + $bl;
17303 $p3c1y = $p3y - $bl * $mag2;
17304 $p4y = $y00 + $bl;
17305 $p4c2y = $p4y;
17306 }
17307
17308 $shadow .= sprintf('%.3F %.3F m ', ($p1x ) * Mpdf::SCALE, ($this->h - ($p1y )) * Mpdf::SCALE);
17309 $shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1c2x) * Mpdf::SCALE, ($this->h - ($p1y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4c2y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE);
17310 $patch_array[0]['f'] = 0;
17311 $patch_array[0]['points'] = [$p1x, $p1y, $p1x, $p1y,
17312 $p2x, $p2c1y, $p2x, $p2y, $p2c2x, $p2y,
17313 $p3x, $p3c1y, $p3x, $p3y, $p3c2x, $p3y,
17314 $p4x, $p4y, $p4x, $p4y, $p4x, $p4c2y,
17315 $p1c2x, $p1y];
17316 $patch_array[0]['colors'] = [$col1, $col2, $col2, $col1];
17317
17318
17319 // RIGHT
17320 $p1x = $x00 + $w00; // control point only matches p3 preceding
17321 $p1y = $y00 + $d1 + $brbgTR_V;
17322 $p2x = $x00 + $w00 - $bl; // control point only matches p4 preceding
17323 $p2y = $y00 + $d1 + $brbgTR_V;
17324 $p3x = $x00 + $w00 - $bl;
17325 $p3y = $y00 + $h00 - $d1 - $brbgBR_V;
17326 $p4x = $x00 + $w00;
17327 $p4c1x = $p4x - $bl / 2;
17328 $p4y = $y00 + $h00 - $d1 - $brbgBR_V;
17329 if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
17330 $p1y = $y00 + $bl;
17331 $p2y = $y00 + $bl;
17332 }
17333 if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
17334 $p3y = $y00 + $h00 - $bl;
17335 $p4y = $y00 + $h00 - $bl;
17336 }
17337
17338 $shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
17339 $patch_array[1]['f'] = 2;
17340 $patch_array[1]['points'] = [$p2x, $p2y,
17341 $p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
17342 $p4c1x, $p4y, $p4x, $p4y, $p4x, $p4y,
17343 $p1x, $p1y];
17344 $patch_array[1]['colors'] = [$col1, $col2];
17345
17346
17347 // BOTTOM RIGHT corner
17348 $p1x = $x00 + $w00 - $bl; // control points only matches p3 preceding
17349 $p1y = $y00 + $h00 - $d1 - $brbgBR_V;
17350 $p1c2y = $p1y + ($d2 + $brbgBR_V) * $mag;
17351 $p2x = $x00 + $w00; // control point only matches p4 preceding
17352 $p2y = $y00 + $h00 - $d1 - $brbgBR_V;
17353 $p2c2y = $p2y + ($d1 + $brbgBR_V) * $mag;
17354 $p3x = $x00 + $w00 - $d1 - $brbgBR_H;
17355 $p3c1x = $p3x + ($d1 + $brbgBR_H) * $mag;
17356 $p3y = $y00 + $h00;
17357 $p3c2y = $p3y - $bl / 2;
17358 $p4x = $x00 + $w00 - $d1 - $brbgBR_H;
17359 $p4c2x = $p4x + ($d2 + $brbgBR_H) * $mag;
17360 $p4y = $y00 + $h00 - $bl;
17361
17362 if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
17363 $p1y = $y00 + $h00 - $bl;
17364 $p1c2y = $p1y;
17365 $p2y = $y00 + $h00 - $bl;
17366 $p2c2y = $p2y + $bl * $mag2;
17367 $p3x = $x00 + $w00 - $bl;
17368 $p3c1x = $p3x + $bl * $mag2;
17369 $p4x = $x00 + $w00 - $bl;
17370 $p4c2x = $p4x;
17371 }
17372
17373 $shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1x) * Mpdf::SCALE, ($this->h - ($p1c2y)) * Mpdf::SCALE, ($p4c2x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE);
17374 $patch_array[2]['f'] = 2;
17375 $patch_array[2]['points'] = [$p2x, $p2c2y,
17376 $p3c1x, $p3y, $p3x, $p3y, $p3x, $p3c2y,
17377 $p4x, $p4y, $p4x, $p4y, $p4c2x, $p4y,
17378 $p1x, $p1c2y];
17379 $patch_array[2]['colors'] = [$col2, $col1];
17380
17381
17382
17383 // BOTTOM
17384 $p1x = $x00 + $w00 - $d1 - $brbgBR_H; // control point only matches p3 preceding
17385 $p1y = $y00 + $h00;
17386 $p2x = $x00 + $w00 - $d1 - $brbgBR_H; // control point only matches p4 preceding
17387 $p2y = $y00 + $h00 - $bl;
17388 $p3x = $x00 + $d1 + $brbgBL_H;
17389 $p3y = $y00 + $h00 - $bl;
17390 $p4x = $x00 + $d1 + $brbgBL_H;
17391 $p4y = $y00 + $h00;
17392 $p4c1y = $p4y - $bl / 2;
17393
17394 if (-$d2 > min($brbgBR_H, $brbgBR_V) || $flatten) {
17395 $p1x = $x00 + $w00 - $bl;
17396 $p2x = $x00 + $w00 - $bl;
17397 }
17398 if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
17399 $p3x = $x00 + $bl;
17400 $p4x = $x00 + $bl;
17401 }
17402
17403 $shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
17404 $patch_array[3]['f'] = 2;
17405 $patch_array[3]['points'] = [$p2x, $p2y,
17406 $p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
17407 $p4x, $p4c1y, $p4x, $p4y, $p4x, $p4y,
17408 $p1x, $p1y];
17409 $patch_array[3]['colors'] = [$col1, $col2];
17410
17411 // BOTTOM LEFT corner
17412 $p1x = $x00 + $d1 + $brbgBL_H;
17413 $p1c2x = $p1x - ($d2 + $brbgBL_H) * $mag; // control points only matches p3 preceding
17414 $p1y = $y00 + $h00 - $bl;
17415 $p2x = $x00 + $d1 + $brbgBL_H;
17416 $p2c2x = $p2x - ($d1 + $brbgBL_H) * $mag; // control point only matches p4 preceding
17417 $p2y = $y00 + $h00;
17418 $p3x = $x00;
17419 $p3c2x = $p3x + $bl / 2;
17420 $p3y = $y00 + $h00 - $d1 - $brbgBL_V;
17421 $p3c1y = $p3y + ($d1 + $brbgBL_V) * $mag;
17422 $p4x = $x00 + $bl;
17423 $p4y = $y00 + $h00 - $d1 - $brbgBL_V;
17424 $p4c2y = $p4y + ($d2 + $brbgBL_V) * $mag;
17425 if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
17426 $p1x = $x00 + $bl;
17427 $p1c2x = $p1x;
17428 $p2x = $x00 + $bl;
17429 $p2c2x = $p2x - $bl * $mag2;
17430 $p3y = $y00 + $h00 - $bl;
17431 $p3c1y = $p3y + $bl * $mag2;
17432 $p4y = $y00 + $h00 - $bl;
17433 $p4c2y = $p4y;
17434 }
17435
17436 $shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1c2x) * Mpdf::SCALE, ($this->h - ($p1y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4c2y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE);
17437 $patch_array[4]['f'] = 2;
17438 $patch_array[4]['points'] = [$p2c2x, $p2y,
17439 $p3x, $p3c1y, $p3x, $p3y, $p3c2x, $p3y,
17440 $p4x, $p4y, $p4x, $p4y, $p4x, $p4c2y,
17441 $p1c2x, $p1y];
17442 $patch_array[4]['colors'] = [$col2, $col1];
17443
17444
17445 // LEFT - joins on the right (C3-C4 of previous): f = 2
17446 $p1x = $x00; // control point only matches p3 preceding
17447 $p1y = $y00 + $h00 - $d1 - $brbgBL_V;
17448 $p2x = $x00 + $bl; // control point only matches p4 preceding
17449 $p2y = $y00 + $h00 - $d1 - $brbgBL_V;
17450 $p3x = $x00 + $bl;
17451 $p3y = $y00 + $d1 + $brbgTL_V;
17452 $p4x = $x00;
17453 $p4c1x = $p4x + $bl / 2;
17454 $p4y = $y00 + $d1 + $brbgTL_V;
17455 if (-$d2 > min($brbgBL_H, $brbgBL_V) || $flatten) {
17456 $p1y = $y00 + $h00 - $bl;
17457 $p2y = $y00 + $h00 - $bl;
17458 }
17459 if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
17460 $p3y = $y00 + $bl;
17461 $p4y = $y00 + $bl;
17462 }
17463
17464 $shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
17465 $patch_array[5]['f'] = 2;
17466 $patch_array[5]['points'] = [$p2x, $p2y,
17467 $p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
17468 $p4c1x, $p4y, $p4x, $p4y, $p4x, $p4y,
17469 $p1x, $p1y];
17470 $patch_array[5]['colors'] = [$col1, $col2];
17471
17472 // TOP LEFT corner
17473 $p1x = $x00 + $bl; // control points only matches p3 preceding
17474 $p1y = $y00 + $d1 + $brbgTL_V;
17475 $p1c2y = $p1y - ($d2 + $brbgTL_V) * $mag;
17476 $p2x = $x00; // control point only matches p4 preceding
17477 $p2y = $y00 + $d1 + $brbgTL_V;
17478 $p2c2y = $p2y - ($d1 + $brbgTL_V) * $mag;
17479 $p3x = $x00 + $d1 + $brbgTL_H;
17480 $p3c1x = $p3x - ($d1 + $brbgTL_H) * $mag;
17481 $p3y = $y00;
17482 $p3c2y = $p3y + $bl / 2;
17483 $p4x = $x00 + $d1 + $brbgTL_H;
17484 $p4c2x = $p4x - ($d2 + $brbgTL_H) * $mag;
17485 $p4y = $y00 + $bl;
17486
17487 if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
17488 $p1y = $y00 + $bl;
17489 $p1c2y = $p1y;
17490 $p2y = $y00 + $bl;
17491 $p2c2y = $p2y - $bl * $mag2;
17492 $p3x = $x00 + $bl;
17493 $p3c1x = $p3x - $bl * $mag2;
17494 $p4x = $x00 + $bl;
17495 $p4c2x = $p4x;
17496 }
17497
17498 $shadow .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($p1x) * Mpdf::SCALE, ($this->h - ($p1c2y)) * Mpdf::SCALE, ($p4c2x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE, ($p4x) * Mpdf::SCALE, ($this->h - ($p4y)) * Mpdf::SCALE);
17499 $patch_array[6]['f'] = 2;
17500 $patch_array[6]['points'] = [$p2x, $p2c2y,
17501 $p3c1x, $p3y, $p3x, $p3y, $p3x, $p3c2y,
17502 $p4x, $p4y, $p4x, $p4y, $p4c2x, $p4y,
17503 $p1x, $p1c2y];
17504 $patch_array[6]['colors'] = [$col2, $col1];
17505
17506
17507 // TOP - joins on the right (C3-C4 of previous): f = 2
17508 $p1x = $x00 + $d1 + $brbgTL_H; // control point only matches p3 preceding
17509 $p1y = $y00;
17510 $p2x = $x00 + $d1 + $brbgTL_H; // control point only matches p4 preceding
17511 $p2y = $y00 + $bl;
17512 $p3x = $x00 + $w00 - $d1 - $brbgTR_H;
17513 $p3y = $y00 + $bl;
17514 $p4x = $x00 + $w00 - $d1 - $brbgTR_H;
17515 $p4y = $y00;
17516 $p4c1y = $p4y + $bl / 2;
17517 if (-$d2 > min($brbgTL_H, $brbgTL_V) || $flatten) {
17518 $p1x = $x00 + $bl;
17519 $p2x = $x00 + $bl;
17520 }
17521 if (-$d2 > min($brbgTR_H, $brbgTR_V) || $flatten) {
17522 $p3x = $x00 + $w00 - $bl;
17523 $p4x = $x00 + $w00 - $bl;
17524 }
17525
17526 $shadow .= sprintf('%.3F %.3F l ', ($p3x ) * Mpdf::SCALE, ($this->h - ($p3y )) * Mpdf::SCALE);
17527 $patch_array[7]['f'] = 2;
17528 $patch_array[7]['points'] = [$p2x, $p2y,
17529 $p3x, $p3y, $p3x, $p3y, $p3x, $p3y,
17530 $p4x, $p4c1y, $p4x, $p4y, $p4x, $p4y,
17531 $p1x, $p1y];
17532 $patch_array[7]['colors'] = [$col1, $col2];
17533
17534 $shadow .= ' h f Q ' . "\n"; // Close path and Fill the inner solid shadow
17535
17536 if ($bl) {
17537 $shadow .= $this->gradient->CoonsPatchMesh($x00, $y00, $w00, $h00, $patch_array, $x00, $x00 + $w00, $y00, $y00 + $h00, $colspace, true);
17538 }
17539
17540 if ($sh['x'] || $sh['y']) {
17541 $shadow .= ' Q' . "\n"; // Shadow Offset
17542 }
17543 $shadow .= ' Q' . "\n"; // Ends path no-op & Sets the clipping path
17544 }
17545 }
17546
17547 $s .= ' W n '; // Ends path no-op & Sets the clipping path
17548
17549 if ($this->blk[$blvl]['bgcolor']) {
17550 $this->pageBackgrounds[$blvl][] = [
17551 'x' => $x0,
17552 'y' => $y0,
17553 'w' => $w,
17554 'h' => $h,
17555 'col' => $this->blk[$blvl]['bgcolorarray'],
17556 'clippath' => $s,
17557 'visibility' => $this->visibility,
17558 'shadow' => $shadow,
17559 'z-index' => $this->current_layer,
17560 ];
17561 } elseif ($shadow) {
17562 $this->pageBackgrounds[$blvl][] = [
17563 'x' => 0,
17564 'y' => 0,
17565 'w' => 0,
17566 'h' => 0,
17567 'shadowonly' => true,
17568 'col' => '',
17569 'clippath' => '',
17570 'visibility' => $this->visibility,
17571 'shadow' => $shadow,
17572 'z-index' => $this->current_layer,
17573 ];
17574 }
17575
17576 /* -- BACKGROUNDS -- */
17577 if (isset($this->blk[$blvl]['gradient'])) {
17578 $g = $this->gradient->parseBackgroundGradient($this->blk[$blvl]['gradient']);
17579 if ($g) {
17580 $gx = $x0;
17581 $gy = $y0;
17582 $this->pageBackgrounds[$blvl][] = [
17583 'gradient' => true,
17584 'x' => $gx,
17585 'y' => $gy,
17586 'w' => $w,
17587 'h' => $h,
17588 'gradtype' => $g['type'],
17589 'stops' => $g['stops'],
17590 'colorspace' => $g['colorspace'],
17591 'coords' => $g['coords'],
17592 'extend' => $g['extend'],
17593 'clippath' => $s,
17594 'visibility' => $this->visibility,
17595 'z-index' => $this->current_layer
17596 ];
17597 }
17598 }
17599
17600 if (isset($this->blk[$blvl]['background-image'])) {
17601 if (isset($this->blk[$blvl]['background-image']['gradient']) && $this->blk[$blvl]['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $this->blk[$blvl]['background-image']['gradient'])) {
17602 $g = $this->gradient->parseMozGradient($this->blk[$blvl]['background-image']['gradient']);
17603 if ($g) {
17604 $gx = $x0;
17605 $gy = $y0;
17606 // origin specifies the background-positioning-area (bpa)
17607 if ($this->blk[$blvl]['background-image']['origin'] == 'padding-box') {
17608 $gx += $this->blk[$blvl]['border_left']['w'];
17609 $w -= ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['border_right']['w']);
17610 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
17611 $gy += $this->blk[$blvl]['border_top']['w'];
17612 }
17613 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
17614 $gy1 = $y1 - $this->blk[$blvl]['border_bottom']['w'];
17615 } else {
17616 $gy1 = $y1;
17617 }
17618 $h = $gy1 - $gy;
17619 } elseif ($this->blk[$blvl]['background-image']['origin'] == 'content-box') {
17620 $gx += $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
17621 $w -= ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'] + $this->blk[$blvl]['border_right']['w'] + $this->blk[$blvl]['padding_right']);
17622 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
17623 $gy += $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
17624 }
17625 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
17626 $gy1 = $y1 - ($this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom']);
17627 } else {
17628 $gy1 = $y1 - $this->blk[$blvl]['padding_bottom'];
17629 }
17630 $h = $gy1 - $gy;
17631 }
17632
17633 if (isset($this->blk[$blvl]['background-image']['size']['w']) && $this->blk[$blvl]['background-image']['size']['w']) {
17634 $size = $this->blk[$blvl]['background-image']['size'];
17635 if ($size['w'] != 'contain' && $size['w'] != 'cover') {
17636 if (stristr($size['w'], '%')) {
17637 $size['w'] = (float) $size['w'];
17638 $size['w'] /= 100;
17639 $w *= $size['w'];
17640 } elseif ($size['w'] != 'auto') {
17641 $w = $size['w'];
17642 }
17643 if (stristr($size['h'], '%')) {
17644 $size['h'] = (float) $size['h'];
17645 $size['h'] /= 100;
17646 $h *= $size['h'];
17647 } elseif ($size['h'] != 'auto') {
17648 $h = $size['h'];
17649 }
17650 }
17651 }
17652 $this->pageBackgrounds[$blvl][] = [
17653 'gradient' => true,
17654 'x' => $gx,
17655 'y' => $gy,
17656 'w' => $w,
17657 'h' => $h,
17658 'gradtype' => $g['type'],
17659 'stops' => $g['stops'],
17660 'colorspace' => $g['colorspace'],
17661 'coords' => $g['coords'],
17662 'extend' => $g['extend'],
17663 'clippath' => $s,
17664 'visibility' => $this->visibility,
17665 'z-index' => $this->current_layer
17666 ];
17667 }
17668
17669 } else {
17670
17671 $image_id = $this->blk[$blvl]['background-image']['image_id'];
17672 $orig_w = $this->blk[$blvl]['background-image']['orig_w'];
17673 $orig_h = $this->blk[$blvl]['background-image']['orig_h'];
17674 $x_pos = $this->blk[$blvl]['background-image']['x_pos'];
17675 $y_pos = $this->blk[$blvl]['background-image']['y_pos'];
17676 $x_repeat = $this->blk[$blvl]['background-image']['x_repeat'];
17677 $y_repeat = $this->blk[$blvl]['background-image']['y_repeat'];
17678 $resize = $this->blk[$blvl]['background-image']['resize'];
17679 $opacity = $this->blk[$blvl]['background-image']['opacity'];
17680 $itype = $this->blk[$blvl]['background-image']['itype'];
17681 $size = $this->blk[$blvl]['background-image']['size'];
17682 // origin specifies the background-positioning-area (bpa)
17683
17684 $bpa = ['x' => $x0, 'y' => $y0, 'w' => $w, 'h' => $h];
17685
17686 if ($this->blk[$blvl]['background-image']['origin'] == 'padding-box') {
17687
17688 $bpa['x'] = $x0 + $this->blk[$blvl]['border_left']['w'];
17689 $bpa['w'] = $w - ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['border_right']['w']);
17690 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
17691 $bpa['y'] = $y0 + $this->blk[$blvl]['border_top']['w'];
17692 } else {
17693 $bpa['y'] = $y0;
17694 }
17695 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
17696 $bpay = $y1 - $this->blk[$blvl]['border_bottom']['w'];
17697 } else {
17698 $bpay = $y1;
17699 }
17700 $bpa['h'] = $bpay - $bpa['y'];
17701
17702 } elseif ($this->blk[$blvl]['background-image']['origin'] == 'content-box') {
17703
17704 $bpa['x'] = $x0 + $this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'];
17705 $bpa['w'] = $w - ($this->blk[$blvl]['border_left']['w'] + $this->blk[$blvl]['padding_left'] + $this->blk[$blvl]['border_right']['w'] + $this->blk[$blvl]['padding_right']);
17706 if ($this->blk[$blvl]['border_top'] && $divider != 'pagetop' && !$continuingpage) {
17707 $bpa['y'] = $y0 + $this->blk[$blvl]['border_top']['w'] + $this->blk[$blvl]['padding_top'];
17708 } else {
17709 $bpa['y'] = $y0 + $this->blk[$blvl]['padding_top'];
17710 }
17711 if ($this->blk[$blvl]['border_bottom'] && $blockstate != 1 && $divider != 'pagebottom') {
17712 $bpay = $y1 - ($this->blk[$blvl]['border_bottom']['w'] + $this->blk[$blvl]['padding_bottom']);
17713 } else {
17714 $bpay = $y1 - $this->blk[$blvl]['padding_bottom'];
17715 }
17716 $bpa['h'] = $bpay - $bpa['y'];
17717
17718 }
17719
17720 $this->pageBackgrounds[$blvl][] = [
17721 'x' => $x0,
17722 'y' => $y0,
17723 'w' => $w,
17724 'h' => $h,
17725 'image_id' => $image_id,
17726 'orig_w' => $orig_w,
17727 'orig_h' => $orig_h,
17728 'x_pos' => $x_pos,
17729 'y_pos' => $y_pos,
17730 'x_repeat' => $x_repeat,
17731 'y_repeat' => $y_repeat,
17732 'clippath' => $s,
17733 'resize' => $resize,
17734 'opacity' => $opacity,
17735 'itype' => $itype,
17736 'visibility' => $this->visibility,
17737 'z-index' => $this->current_layer,
17738 'size' => $size,
17739 'bpa' => $bpa
17740 ];
17741 }
17742 }
17743 /* -- END BACKGROUNDS -- */
17744
17745 // Float DIV
17746 $this->blk[$blvl]['bb_painted'][$this->page] = true;
17747 }
17748 /* -- BORDER-RADIUS -- */
17749
17750 function _EllipseArc($x0, $y0, $rx, $ry, $seg = 1, $part = false, $start = false)
17751 {
17752 // Anticlockwise segment 1-4 TR-TL-BL-BR (part=1 or 2)
17753 $s = '';
17754
17755 if ($rx < 0) {
17756 $rx = 0;
17757 }
17758
17759 if ($ry < 0) {
17760 $ry = 0;
17761 }
17762
17763 $rx *= Mpdf::SCALE;
17764 $ry *= Mpdf::SCALE;
17765
17766 $astart = 0;
17767
17768 if ($seg == 1) { // Top Right
17769 $afinish = 90;
17770 $nSeg = 4;
17771 } elseif ($seg == 2) { // Top Left
17772 $afinish = 180;
17773 $nSeg = 8;
17774 } elseif ($seg == 3) { // Bottom Left
17775 $afinish = 270;
17776 $nSeg = 12;
17777 } else { // Bottom Right
17778 $afinish = 360;
17779 $nSeg = 16;
17780 }
17781
17782 $astart = deg2rad((float) $astart);
17783 $afinish = deg2rad((float) $afinish);
17784
17785 $totalAngle = $afinish - $astart;
17786 $dt = $totalAngle / $nSeg; // segment angle
17787 $dtm = $dt / 3;
17788 $x0 *= Mpdf::SCALE;
17789 $y0 = ($this->h - $y0) * Mpdf::SCALE;
17790 $t1 = $astart;
17791 $a0 = $x0 + ($rx * cos($t1));
17792 $b0 = $y0 + ($ry * sin($t1));
17793 $c0 = -$rx * sin($t1);
17794 $d0 = $ry * cos($t1);
17795 $op = false;
17796
17797 for ($i = 1; $i <= $nSeg; $i++) {
17798 // Draw this bit of the total curve
17799 $t1 = ($i * $dt) + $astart;
17800 $a1 = $x0 + ($rx * cos($t1));
17801 $b1 = $y0 + ($ry * sin($t1));
17802 $c1 = -$rx * sin($t1);
17803 $d1 = $ry * cos($t1);
17804 if ($i > ($nSeg - 4) && (!$part || ($part == 1 && $i <= $nSeg - 2) || ($part == 2 && $i > $nSeg - 2))) {
17805 if ($start && !$op) {
17806 $s .= sprintf('%.3F %.3F m ', $a0, $b0);
17807 }
17808 $s .= sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c ', ($a0 + ($c0 * $dtm)), ($b0 + ($d0 * $dtm)), ($a1 - ($c1 * $dtm)), ($b1 - ($d1 * $dtm)), $a1, $b1);
17809 $op = true;
17810 }
17811 $a0 = $a1;
17812 $b0 = $b1;
17813 $c0 = $c1;
17814 $d0 = $d1;
17815 }
17816
17817 return $s;
17818 }
17819
17820 /* -- END BORDER-RADIUS -- */
17821
17822 function PaintDivLnBorder($state = 0, $blvl = 0, $h = 0)
17823 {
17824 // $state = 0 normal; 1 top; 2 bottom; 3 top and bottom
17825 $this->ColDetails[$this->CurrCol]['bottom_margin'] = $this->y + $h;
17826
17827 $save_y = $this->y;
17828
17829 $w = $this->blk[$blvl]['width'];
17830 $x0 = $this->x; // left
17831 $y0 = $this->y; // top
17832 $x1 = $this->x + $w; // bottom
17833 $y1 = $this->y + $h; // bottom
17834 $continuingpage = (isset($this->blk[$blvl]['startpage']) && $this->blk[$blvl]['startpage'] != $this->page);
17835
17836 if ($this->blk[$blvl]['border_top'] && ($state == 1 || $state == 3)) {
17837 $tbd = $this->blk[$blvl]['border_top'];
17838 if (isset($tbd['s']) && $tbd['s']) {
17839 $this->_setBorderLine($tbd);
17840 $this->y = $y0 + ($tbd['w'] / 2);
17841 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17842 $this->_setDashBorder($tbd['style'], '', $continuingpage, 'T');
17843 $this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $this->y);
17844 } else {
17845 $this->SetLineJoin(0);
17846 $this->SetLineCap(0);
17847 $this->Line($x0, $this->y, $x0 + $w, $this->y);
17848 }
17849 $this->y += $tbd['w'];
17850 // Reset Corners and Dash off
17851 $this->SetLineJoin(2);
17852 $this->SetLineCap(2);
17853 $this->SetDash();
17854 }
17855 }
17856 if ($this->blk[$blvl]['border_left']) {
17857 $tbd = $this->blk[$blvl]['border_left'];
17858 if (isset($tbd['s']) && $tbd['s']) {
17859 $this->_setBorderLine($tbd);
17860 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17861 $this->y = $y0 + ($tbd['w'] / 2);
17862 $this->_setDashBorder($tbd['style'], '', $continuingpage, 'L');
17863 $this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + ($tbd['w'] / 2), $y0 + $h - ($tbd['w'] / 2));
17864 } else {
17865 $this->y = $y0;
17866 $this->SetLineJoin(0);
17867 $this->SetLineCap(0);
17868 $this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + ($tbd['w'] / 2), $y0 + $h);
17869 }
17870 $this->y += $tbd['w'];
17871 // Reset Corners and Dash off
17872 $this->SetLineJoin(2);
17873 $this->SetLineCap(2);
17874 $this->SetDash();
17875 }
17876 }
17877 if ($this->blk[$blvl]['border_right']) {
17878 $tbd = $this->blk[$blvl]['border_right'];
17879 if (isset($tbd['s']) && $tbd['s']) {
17880 $this->_setBorderLine($tbd);
17881 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17882 $this->y = $y0 + ($tbd['w'] / 2);
17883 $this->_setDashBorder($tbd['style'], '', $continuingpage, 'R');
17884 $this->Line($x0 + $w - ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $y0 + $h - ($tbd['w'] / 2));
17885 } else {
17886 $this->y = $y0;
17887 $this->SetLineJoin(0);
17888 $this->SetLineCap(0);
17889 $this->Line($x0 + $w - ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $y0 + $h);
17890 }
17891 $this->y += $tbd['w'];
17892 // Reset Corners and Dash off
17893 $this->SetLineJoin(2);
17894 $this->SetLineCap(2);
17895 $this->SetDash();
17896 }
17897 }
17898 if ($this->blk[$blvl]['border_bottom'] && $state > 1) {
17899 $tbd = $this->blk[$blvl]['border_bottom'];
17900 if (isset($tbd['s']) && $tbd['s']) {
17901 $this->_setBorderLine($tbd);
17902 $this->y = $y0 + $h - ($tbd['w'] / 2);
17903 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17904 $this->_setDashBorder($tbd['style'], '', $continuingpage, 'B');
17905 $this->Line($x0 + ($tbd['w'] / 2), $this->y, $x0 + $w - ($tbd['w'] / 2), $this->y);
17906 } else {
17907 $this->SetLineJoin(0);
17908 $this->SetLineCap(0);
17909 $this->Line($x0, $this->y, $x0 + $w, $this->y);
17910 }
17911 $this->y += $tbd['w'];
17912 // Reset Corners and Dash off
17913 $this->SetLineJoin(2);
17914 $this->SetLineCap(2);
17915 $this->SetDash();
17916 }
17917 }
17918 $this->SetDash();
17919 $this->y = $save_y;
17920 }
17921
17922 function PaintImgBorder($objattr, $is_table)
17923 {
17924 // Borders are disabled in columns - messes up the repositioning in printcolumnbuffer
17925 if ($this->ColActive) {
17926 return;
17927 } // *COLUMNS*
17928 if ($is_table) {
17929 $k = $this->shrin_k;
17930 } else {
17931 $k = 1;
17932 }
17933 $h = (isset($objattr['BORDER-HEIGHT']) ? $objattr['BORDER-HEIGHT'] : 0);
17934 $w = (isset($objattr['BORDER-WIDTH']) ? $objattr['BORDER-WIDTH'] : 0);
17935 $x0 = (isset($objattr['BORDER-X']) ? $objattr['BORDER-X'] : 0);
17936 $y0 = (isset($objattr['BORDER-Y']) ? $objattr['BORDER-Y'] : 0);
17937
17938 // BORDERS
17939 if ($objattr['border_top']) {
17940 $tbd = $objattr['border_top'];
17941 if (!empty($tbd['s'])) {
17942 $this->_setBorderLine($tbd, $k);
17943 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17944 $this->_setDashBorder($tbd['style'], '', '', 'T');
17945 }
17946 $this->Line($x0, $y0, $x0 + $w, $y0);
17947 // Reset Corners and Dash off
17948 $this->SetLineJoin(2);
17949 $this->SetLineCap(2);
17950 $this->SetDash();
17951 }
17952 }
17953 if ($objattr['border_left']) {
17954 $tbd = $objattr['border_left'];
17955 if (!empty($tbd['s'])) {
17956 $this->_setBorderLine($tbd, $k);
17957 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17958 $this->_setDashBorder($tbd['style'], '', '', 'L');
17959 }
17960 $this->Line($x0, $y0, $x0, $y0 + $h);
17961 // Reset Corners and Dash off
17962 $this->SetLineJoin(2);
17963 $this->SetLineCap(2);
17964 $this->SetDash();
17965 }
17966 }
17967 if ($objattr['border_right']) {
17968 $tbd = $objattr['border_right'];
17969 if (!empty($tbd['s'])) {
17970 $this->_setBorderLine($tbd, $k);
17971 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17972 $this->_setDashBorder($tbd['style'], '', '', 'R');
17973 }
17974 $this->Line($x0 + $w, $y0, $x0 + $w, $y0 + $h);
17975 // Reset Corners and Dash off
17976 $this->SetLineJoin(2);
17977 $this->SetLineCap(2);
17978 $this->SetDash();
17979 }
17980 }
17981 if ($objattr['border_bottom']) {
17982 $tbd = $objattr['border_bottom'];
17983 if (!empty($tbd['s'])) {
17984 $this->_setBorderLine($tbd, $k);
17985 if ($tbd['style'] == 'dotted' || $tbd['style'] == 'dashed') {
17986 $this->_setDashBorder($tbd['style'], '', '', 'B');
17987 }
17988 $this->Line($x0, $y0 + $h, $x0 + $w, $y0 + $h);
17989 // Reset Corners and Dash off
17990 $this->SetLineJoin(2);
17991 $this->SetLineCap(2);
17992 $this->SetDash();
17993 }
17994 }
17995 $this->SetDash();
17996 $this->SetAlpha(1);
17997 }
17998
17999 /* -- END HTML-CSS -- */
18000
18001 function Reset()
18002 {
18003 $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
18004 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
18005 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
18006 $this->SetAlpha(1);
18007 $this->colorarray = '';
18008
18009 $this->spanbgcolorarray = '';
18010 $this->spanbgcolor = false;
18011 $this->spanborder = false;
18012 $this->spanborddet = [];
18013
18014 $this->ResetStyles();
18015
18016 $this->HREF = '';
18017 $this->textparam = [];
18018 $this->SetTextOutline();
18019
18020 $this->textvar = 0x00; // mPDF 5.7.1
18021 $this->OTLtags = [];
18022 $this->textshadow = '';
18023
18024 $this->currentLang = $this->default_lang; // mPDF 6
18025 $this->RestrictUnicodeFonts($this->default_available_fonts); // mPDF 6
18026 $this->SetFont($this->default_font, '', 0, false);
18027 $this->SetFontSize($this->default_font_size, false);
18028
18029 $this->currentfontfamily = '';
18030 $this->currentfontsize = '';
18031 $this->currentfontstyle = '';
18032
18033 if ($this->tableLevel && isset($this->table[1][1]['cellLineHeight'])) {
18034 $this->SetLineHeight('', $this->table[1][1]['cellLineHeight']);
18035 } else {
18036 if (isset($this->blk[$this->blklvl]['line_height']) && $this->blk[$this->blklvl]['line_height']) {
18037 $this->SetLineHeight('', $this->blk[$this->blklvl]['line_height']); // sets default line height
18038 }
18039 }
18040
18041 $this->lSpacingCSS = '';
18042 $this->wSpacingCSS = '';
18043 $this->fixedlSpacing = false;
18044 $this->minwSpacing = 0;
18045 $this->SetDash(); // restore to no dash
18046 $this->dash_on = false;
18047 $this->dotted_on = false;
18048 $this->divwidth = 0;
18049 $this->divheight = 0;
18050 $this->cellTextAlign = '';
18051 $this->cellLineHeight = '';
18052 $this->cellLineStackingStrategy = '';
18053 $this->cellLineStackingShift = '';
18054 $this->oldy = -1;
18055
18056 $bodystyle = [];
18057
18058 if (isset($this->cssManager->CSS['BODY']['FONT-STYLE'])) {
18059 $bodystyle['FONT-STYLE'] = $this->cssManager->CSS['BODY']['FONT-STYLE'];
18060 }
18061
18062 if (isset($this->cssManager->CSS['BODY']['FONT-WEIGHT'])) {
18063 $bodystyle['FONT-WEIGHT'] = $this->cssManager->CSS['BODY']['FONT-WEIGHT'];
18064 }
18065
18066 if (isset($this->cssManager->CSS['BODY']['COLOR'])) {
18067 $bodystyle['COLOR'] = $this->cssManager->CSS['BODY']['COLOR'];
18068 }
18069
18070 if (isset($bodystyle)) {
18071 $this->setCSS($bodystyle, 'BLOCK', 'BODY');
18072 }
18073 }
18074
18075 /* -- HTML-CSS -- */
18076
18078 {
18079 // changes anykey=anyvalue to anykey="anyvalue" (only do this when this happens inside tags)
18080 $regexp = '/ (\\w+?)=([^\\s>"]+)/si';
18081 $html = preg_replace($regexp, " \$1=\"\$2\"", $html);
18082 if (preg_match('/<title>(.*?)<\/title>/si', $html, $m)) {
18083 $this->SetTitle($m[1]);
18084 }
18085 preg_match_all('/<meta [^>]*?(name|content)="([^>]*?)" [^>]*?(name|content)="([^>]*?)".*?>/si', $html, $aux);
18086 $firstattr = $aux[1];
18087 $secondattr = $aux[3];
18088 for ($i = 0; $i < count($aux[0]); $i++) {
18089 $name = ( strtoupper($firstattr[$i]) == "NAME" ) ? strtoupper($aux[2][$i]) : strtoupper($aux[4][$i]);
18090 $content = ( strtoupper($firstattr[$i]) == "CONTENT" ) ? $aux[2][$i] : $aux[4][$i];
18091 switch ($name) {
18092 case "KEYWORDS":
18093 $this->SetKeywords($content);
18094 break;
18095 case "AUTHOR":
18096 $this->SetAuthor($content);
18097 break;
18098 case "DESCRIPTION":
18099 $this->SetSubject($content);
18100 break;
18101 }
18102 }
18103 }
18104
18106 {
18107 // Charset conversion
18108 if ($this->allow_charset_conversion) {
18109 if (preg_match('/<head.*charset=([^\'\"\s]*).*<\/head>/si', $html, $m)) {
18110 if (strtoupper($m[1]) != 'UTF-8') {
18111 $this->charset_in = strtoupper($m[1]);
18112 }
18113 }
18114 }
18115 }
18116
18117 function setCSS($arrayaux, $type = '', $tag = '')
18118 {
18119 // type= INLINE | BLOCK | TABLECELL // tag= BODY
18120 if (!is_array($arrayaux)) {
18121 return; // Removes PHP Warning
18122 }
18123
18124 // mPDF 5.7.3 inline text-decoration parameters
18125 $preceeding_fontkey = $this->FontFamily . $this->FontStyle;
18126 $preceeding_fontsize = $this->FontSize;
18127 $spanbordset = false;
18128 $spanbgset = false;
18129 // mPDF 6
18130 $prevlevel = (($this->blklvl == 0) ? 0 : $this->blklvl - 1);
18131
18132 // Set font size first so that e.g. MARGIN 0.83em works on font size for this element
18133 if (isset($arrayaux['FONT-SIZE'])) {
18134 $v = $arrayaux['FONT-SIZE'];
18135 $firstLetter = substr($v, 0, 1);
18136 if (is_numeric($firstLetter) || ($firstLetter === '.')) {
18137 if ($type == 'BLOCK' && $this->blklvl > 0 && isset($this->blk[$this->blklvl - 1]['InlineProperties']) && isset($this->blk[$this->blklvl - 1]['InlineProperties']['size'])) {
18138 $mmsize = $this->sizeConverter->convert($v, $this->blk[$this->blklvl - 1]['InlineProperties']['size']);
18139 } elseif ($type == 'TABLECELL') {
18140 $mmsize = $this->sizeConverter->convert($v, $this->default_font_size / Mpdf::SCALE);
18141 } else {
18142 $mmsize = $this->sizeConverter->convert($v, $this->FontSize);
18143 }
18144 $this->SetFontSize($mmsize * (Mpdf::SCALE), false); // Get size in points (pt)
18145 } else {
18146 $v = strtoupper($v);
18147 if (isset($this->fontsizes[$v])) {
18148 $this->SetFontSize($this->fontsizes[$v] * $this->default_font_size, false);
18149 }
18150 }
18151 if ($tag == 'BODY') {
18152 $this->SetDefaultFontSize($this->FontSizePt);
18153 }
18154 }
18155
18156 // mPDF 6
18157 if (isset($arrayaux['LANG']) && $arrayaux['LANG']) {
18158 if ($this->autoLangToFont && !$this->usingCoreFont) {
18159 if ($arrayaux['LANG'] != $this->default_lang && $arrayaux['LANG'] != 'UTF-8') {
18160 list ($coreSuitable, $mpdf_pdf_unifont) = $this->languageToFont->getLanguageOptions($arrayaux['LANG'], $this->useAdobeCJK);
18161 if ($mpdf_pdf_unifont) {
18162 $arrayaux['FONT-FAMILY'] = $mpdf_pdf_unifont;
18163 }
18164 if ($tag == 'BODY') {
18165 $this->default_lang = $arrayaux['LANG'];
18166 }
18167 }
18168 }
18169 $this->currentLang = $arrayaux['LANG'];
18170 }
18171
18172 // FOR INLINE and BLOCK OR 'BODY'
18173 if (isset($arrayaux['FONT-FAMILY'])) {
18174 $v = $arrayaux['FONT-FAMILY'];
18175 // If it is a font list, get all font types
18176 $aux_fontlist = explode(",", $v);
18177 $found = 0;
18178 foreach ($aux_fontlist as $f) {
18179 $fonttype = trim($f);
18180 $fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
18181 $fonttype = preg_replace('/ /', '', $fonttype);
18182 $v = strtolower(trim($fonttype));
18183 if (isset($this->fonttrans[$v]) && $this->fonttrans[$v]) {
18184 $v = $this->fonttrans[$v];
18185 }
18186 if ((!$this->onlyCoreFonts && in_array($v, $this->available_unifonts)) ||
18187 in_array($v, ['ccourier', 'ctimes', 'chelvetica']) ||
18188 ($this->onlyCoreFonts && in_array($v, ['courier', 'times', 'helvetica', 'arial'])) ||
18189 in_array($v, ['sjis', 'uhc', 'big5', 'gb'])) {
18190 $fonttype = $v;
18191 $found = 1;
18192 break;
18193 }
18194 }
18195 if (!$found) {
18196 foreach ($aux_fontlist as $f) {
18197 $fonttype = trim($f);
18198 $fonttype = preg_replace('/["\']*(.*?)["\']*/', '\\1', $fonttype);
18199 $fonttype = preg_replace('/ /', '', $fonttype);
18200 $v = strtolower(trim($fonttype));
18201 if (isset($this->fonttrans[$v]) && $this->fonttrans[$v]) {
18202 $v = $this->fonttrans[$v];
18203 }
18204 if (in_array($v, $this->sans_fonts) || in_array($v, $this->serif_fonts) || in_array($v, $this->mono_fonts)) {
18205 $fonttype = $v;
18206 break;
18207 }
18208 }
18209 }
18210
18211 if ($tag == 'BODY') {
18212 $this->SetDefaultFont($fonttype);
18213 }
18214 $this->SetFont($fonttype, $this->currentfontstyle, 0, false);
18215 } else {
18216 $this->SetFont($this->currentfontfamily, $this->currentfontstyle, 0, false);
18217 }
18218
18219 foreach ($arrayaux as $k => $v) {
18220 if ($type != 'INLINE' && $tag != 'BODY' && $type != 'TABLECELL') {
18221 switch ($k) {
18222 // BORDERS
18223 case 'BORDER-TOP':
18224 $this->blk[$this->blklvl]['border_top'] = $this->border_details($v);
18225 if ($this->blk[$this->blklvl]['border_top']['s']) {
18226 $this->blk[$this->blklvl]['border'] = 1;
18227 }
18228 break;
18229 case 'BORDER-BOTTOM':
18230 $this->blk[$this->blklvl]['border_bottom'] = $this->border_details($v);
18231 if ($this->blk[$this->blklvl]['border_bottom']['s']) {
18232 $this->blk[$this->blklvl]['border'] = 1;
18233 }
18234 break;
18235 case 'BORDER-LEFT':
18236 $this->blk[$this->blklvl]['border_left'] = $this->border_details($v);
18237 if ($this->blk[$this->blklvl]['border_left']['s']) {
18238 $this->blk[$this->blklvl]['border'] = 1;
18239 }
18240 break;
18241 case 'BORDER-RIGHT':
18242 $this->blk[$this->blklvl]['border_right'] = $this->border_details($v);
18243 if ($this->blk[$this->blklvl]['border_right']['s']) {
18244 $this->blk[$this->blklvl]['border'] = 1;
18245 }
18246 break;
18247
18248 // PADDING
18249 case 'PADDING-TOP':
18250 $this->blk[$this->blklvl]['padding_top'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18251 break;
18252 case 'PADDING-BOTTOM':
18253 $this->blk[$this->blklvl]['padding_bottom'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18254 break;
18255 case 'PADDING-LEFT':
18256 if (($tag == 'UL' || $tag == 'OL') && $v == 'auto') {
18257 $this->blk[$this->blklvl]['padding_left'] = 'auto';
18258 break;
18259 }
18260 $this->blk[$this->blklvl]['padding_left'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18261 break;
18262 case 'PADDING-RIGHT':
18263 if (($tag == 'UL' || $tag == 'OL') && $v == 'auto') {
18264 $this->blk[$this->blklvl]['padding_right'] = 'auto';
18265 break;
18266 }
18267 $this->blk[$this->blklvl]['padding_right'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18268 break;
18269
18270 // MARGINS
18271 case 'MARGIN-TOP':
18272 $tmp = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18273 if (isset($this->blk[$this->blklvl]['lastbottommargin'])) {
18274 if ($tmp > $this->blk[$this->blklvl]['lastbottommargin']) {
18275 $tmp -= $this->blk[$this->blklvl]['lastbottommargin'];
18276 } else {
18277 $tmp = 0;
18278 }
18279 }
18280 $this->blk[$this->blklvl]['margin_top'] = $tmp;
18281 break;
18282 case 'MARGIN-BOTTOM':
18283 $this->blk[$this->blklvl]['margin_bottom'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18284 break;
18285 case 'MARGIN-LEFT':
18286 $this->blk[$this->blklvl]['margin_left'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18287 break;
18288 case 'MARGIN-RIGHT':
18289 $this->blk[$this->blklvl]['margin_right'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18290 break;
18291
18292 /* -- BORDER-RADIUS -- */
18293 case 'BORDER-TOP-LEFT-RADIUS-H':
18294 $this->blk[$this->blklvl]['border_radius_TL_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18295 break;
18296 case 'BORDER-TOP-LEFT-RADIUS-V':
18297 $this->blk[$this->blklvl]['border_radius_TL_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18298 break;
18299 case 'BORDER-TOP-RIGHT-RADIUS-H':
18300 $this->blk[$this->blklvl]['border_radius_TR_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18301 break;
18302 case 'BORDER-TOP-RIGHT-RADIUS-V':
18303 $this->blk[$this->blklvl]['border_radius_TR_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18304 break;
18305 case 'BORDER-BOTTOM-LEFT-RADIUS-H':
18306 $this->blk[$this->blklvl]['border_radius_BL_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18307 break;
18308 case 'BORDER-BOTTOM-LEFT-RADIUS-V':
18309 $this->blk[$this->blklvl]['border_radius_BL_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18310 break;
18311 case 'BORDER-BOTTOM-RIGHT-RADIUS-H':
18312 $this->blk[$this->blklvl]['border_radius_BR_H'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18313 break;
18314 case 'BORDER-BOTTOM-RIGHT-RADIUS-V':
18315 $this->blk[$this->blklvl]['border_radius_BR_V'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18316 break;
18317 /* -- END BORDER-RADIUS -- */
18318
18319 case 'BOX-SHADOW':
18320 $bs = $this->cssManager->setCSSboxshadow($v);
18321 if ($bs) {
18322 $this->blk[$this->blklvl]['box_shadow'] = $bs;
18323 }
18324 break;
18325
18326 case 'BACKGROUND-CLIP':
18327 if (strtoupper($v) == 'PADDING-BOX') {
18328 $this->blk[$this->blklvl]['background_clip'] = 'padding-box';
18329 } elseif (strtoupper($v) == 'CONTENT-BOX') {
18330 $this->blk[$this->blklvl]['background_clip'] = 'content-box';
18331 }
18332 break;
18333
18334 case 'PAGE-BREAK-AFTER':
18335 if (strtoupper($v) == 'AVOID') {
18336 $this->blk[$this->blklvl]['page_break_after_avoid'] = true;
18337 } elseif (strtoupper($v) == 'ALWAYS' || strtoupper($v) == 'LEFT' || strtoupper($v) == 'RIGHT') {
18338 $this->blk[$this->blklvl]['page_break_after'] = strtoupper($v);
18339 }
18340 break;
18341
18342 // mPDF 6 pagebreaktype
18343 case 'BOX-DECORATION-BREAK':
18344 if (strtoupper($v) == 'CLONE') {
18345 $this->blk[$this->blklvl]['box_decoration_break'] = 'clone';
18346 } elseif (strtoupper($v) == 'SLICE') {
18347 $this->blk[$this->blklvl]['box_decoration_break'] = 'slice';
18348 }
18349 break;
18350
18351 case 'WIDTH':
18352 if (strtoupper($v) != 'AUTO') {
18353 $this->blk[$this->blklvl]['css_set_width'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false);
18354 }
18355 break;
18356
18357 // mPDF 6 Lists
18358 // LISTS
18359 case 'LIST-STYLE-TYPE':
18360 $this->blk[$this->blklvl]['list_style_type'] = strtolower($v);
18361 break;
18362 case 'LIST-STYLE-IMAGE':
18363 $this->blk[$this->blklvl]['list_style_image'] = strtolower($v);
18364 break;
18365 case 'LIST-STYLE-POSITION':
18366 $this->blk[$this->blklvl]['list_style_position'] = strtolower($v);
18367 break;
18368 }//end of switch($k)
18369 }
18370
18371
18372 if ($type != 'INLINE' && $type != 'TABLECELL') { // All block-level, including BODY tag
18373 switch ($k) {
18374 case 'TEXT-INDENT':
18375 // Computed value - to inherit
18376 $this->blk[$this->blklvl]['text_indent'] = $this->sizeConverter->convert($v, $this->blk[$prevlevel]['inner_width'], $this->FontSize, false) . 'mm';
18377 break;
18378
18379 case 'MARGIN-COLLAPSE': // Custom tag to collapse margins at top and bottom of page
18380 if (strtoupper($v) == 'COLLAPSE') {
18381 $this->blk[$this->blklvl]['margin_collapse'] = true;
18382 }
18383 break;
18384
18385 case 'LINE-HEIGHT':
18386 $this->blk[$this->blklvl]['line_height'] = $this->fixLineheight($v);
18387 if (!$this->blk[$this->blklvl]['line_height']) {
18388 $this->blk[$this->blklvl]['line_height'] = 'N';
18389 } // mPDF 6
18390 break;
18391
18392 // mPDF 6
18393 case 'LINE-STACKING-STRATEGY':
18394 $this->blk[$this->blklvl]['line_stacking_strategy'] = strtolower($v);
18395 break;
18396
18397 case 'LINE-STACKING-SHIFT':
18398 $this->blk[$this->blklvl]['line_stacking_shift'] = strtolower($v);
18399 break;
18400
18401 case 'TEXT-ALIGN': // left right center justify
18402 switch (strtoupper($v)) {
18403 case 'LEFT':
18404 $this->blk[$this->blklvl]['align'] = "L";
18405 break;
18406 case 'CENTER':
18407 $this->blk[$this->blklvl]['align'] = "C";
18408 break;
18409 case 'RIGHT':
18410 $this->blk[$this->blklvl]['align'] = "R";
18411 break;
18412 case 'JUSTIFY':
18413 $this->blk[$this->blklvl]['align'] = "J";
18414 break;
18415 }
18416 break;
18417
18418 /* -- BACKGROUNDS -- */
18419 case 'BACKGROUND-GRADIENT':
18420 if ($type == 'BLOCK') {
18421 $this->blk[$this->blklvl]['gradient'] = $v;
18422 }
18423 break;
18424 /* -- END BACKGROUNDS -- */
18425
18426 case 'DIRECTION':
18427 if ($v) {
18428 $this->blk[$this->blklvl]['direction'] = strtolower($v);
18429 }
18430 break;
18431 }
18432 }
18433
18434 // FOR INLINE ONLY
18435 if ($type == 'INLINE') {
18436 switch ($k) {
18437 case 'DISPLAY':
18438 if (strtoupper($v) == 'NONE') {
18439 $this->inlineDisplayOff = true;
18440 }
18441 break;
18442 case 'DIRECTION':
18443 break;
18444 }
18445 }
18446 // FOR INLINE ONLY
18447 if ($type == 'INLINE') {
18448 switch ($k) {
18449 // BORDERS
18450 case 'BORDER-TOP':
18451 $this->spanborddet['T'] = $this->border_details($v);
18452 $this->spanborder = true;
18453 $spanbordset = true;
18454 break;
18455 case 'BORDER-BOTTOM':
18456 $this->spanborddet['B'] = $this->border_details($v);
18457 $this->spanborder = true;
18458 $spanbordset = true;
18459 break;
18460 case 'BORDER-LEFT':
18461 $this->spanborddet['L'] = $this->border_details($v);
18462 $this->spanborder = true;
18463 $spanbordset = true;
18464 break;
18465 case 'BORDER-RIGHT':
18466 $this->spanborddet['R'] = $this->border_details($v);
18467 $this->spanborder = true;
18468 $spanbordset = true;
18469 break;
18470 case 'VISIBILITY': // block is set in OpenTag
18471 $v = strtolower($v);
18472 if ($v == 'visible' || $v == 'hidden' || $v == 'printonly' || $v == 'screenonly') {
18473 $this->textparam['visibility'] = $v;
18474 }
18475 break;
18476 }//end of switch($k)
18477 }
18478
18479 if ($type != 'TABLECELL') {
18480 // FOR INLINE and BLOCK
18481 switch ($k) {
18482 case 'TEXT-ALIGN': // left right center justify
18483 if (strtoupper($v) == 'NOJUSTIFY' && $this->blk[$this->blklvl]['align'] == "J") {
18484 $this->blk[$this->blklvl]['align'] = "";
18485 }
18486 break;
18487 // bgcolor only - to stay consistent with original html2fpdf
18488 case 'BACKGROUND':
18489 case 'BACKGROUND-COLOR':
18490 $cor = $this->colorConverter->convert($v, $this->PDFAXwarnings);
18491 if ($cor) {
18492 if ($tag == 'BODY') {
18493 $this->bodyBackgroundColor = $cor;
18494 } elseif ($type == 'INLINE') {
18495 $this->spanbgcolorarray = $cor;
18496 $this->spanbgcolor = true;
18497 $spanbgset = true;
18498 } else {
18499 $this->blk[$this->blklvl]['bgcolorarray'] = $cor;
18500 $this->blk[$this->blklvl]['bgcolor'] = true;
18501 }
18502 } elseif ($type != 'INLINE') {
18503 if ($this->ColActive) {
18504 $this->blk[$this->blklvl]['bgcolorarray'] = $this->blk[$prevlevel]['bgcolorarray'];
18505 $this->blk[$this->blklvl]['bgcolor'] = $this->blk[$prevlevel]['bgcolor'];
18506 }
18507 }
18508 break;
18509
18510 case 'VERTICAL-ALIGN': // super and sub only dealt with here e.g. <SUB> and <SUP>
18511 switch (strtoupper($v)) {
18512 case 'SUPER':
18513 $this->textvar = ($this->textvar | TextVars::FA_SUPERSCRIPT); // mPDF 5.7.1
18514 $this->textvar = ($this->textvar & ~TextVars::FA_SUBSCRIPT);
18515 // mPDF 5.7.3 inline text-decoration parameters
18516 if (isset($this->textparam['text-baseline'])) {
18517 $this->textparam['text-baseline'] += ($this->baselineSup) * $preceeding_fontsize;
18518 } else {
18519 $this->textparam['text-baseline'] = ($this->baselineSup) * $preceeding_fontsize;
18520 }
18521 break;
18522 case 'SUB':
18523 $this->textvar = ($this->textvar | TextVars::FA_SUBSCRIPT);
18524 $this->textvar = ($this->textvar & ~TextVars::FA_SUPERSCRIPT);
18525 // mPDF 5.7.3 inline text-decoration parameters
18526 if (isset($this->textparam['text-baseline'])) {
18527 $this->textparam['text-baseline'] += ($this->baselineSub) * $preceeding_fontsize;
18528 } else {
18529 $this->textparam['text-baseline'] = ($this->baselineSub) * $preceeding_fontsize;
18530 }
18531 break;
18532 case 'BASELINE':
18533 $this->textvar = ($this->textvar & ~TextVars::FA_SUBSCRIPT);
18534 $this->textvar = ($this->textvar & ~TextVars::FA_SUPERSCRIPT);
18535 // mPDF 5.7.3 inline text-decoration parameters
18536 if (isset($this->textparam['text-baseline'])) {
18537 unset($this->textparam['text-baseline']);
18538 }
18539 break;
18540 // mPDF 5.7.3 inline text-decoration parameters
18541 default:
18542 $lh = $this->_computeLineheight($this->blk[$this->blklvl]['line_height']);
18543 $sz = $this->sizeConverter->convert($v, $lh, $this->FontSize, false);
18544 $this->textvar = ($this->textvar & ~TextVars::FA_SUBSCRIPT);
18545 $this->textvar = ($this->textvar & ~TextVars::FA_SUPERSCRIPT);
18546 if ($sz) {
18547 if ($sz > 0) {
18548 $this->textvar = ($this->textvar | TextVars::FA_SUPERSCRIPT);
18549 } else {
18550 $this->textvar = ($this->textvar | TextVars::FA_SUBSCRIPT);
18551 }
18552 if (isset($this->textparam['text-baseline'])) {
18553 $this->textparam['text-baseline'] += $sz;
18554 } else {
18555 $this->textparam['text-baseline'] = $sz;
18556 }
18557 }
18558 }
18559 break;
18560 }//end of switch($k)
18561 }
18562
18563
18564 // FOR ALL
18565 switch ($k) {
18566 case 'LETTER-SPACING':
18567 $this->lSpacingCSS = $v;
18568 if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
18569 $this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize);
18570 }
18571 break;
18572
18573 case 'WORD-SPACING':
18574 $this->wSpacingCSS = $v;
18575 if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
18576 $this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize);
18577 }
18578 break;
18579
18580 case 'FONT-STYLE': // italic normal oblique
18581 switch (strtoupper($v)) {
18582 case 'ITALIC':
18583 case 'OBLIQUE':
18584 $this->SetStyle('I', true);
18585 break;
18586 case 'NORMAL':
18587 $this->SetStyle('I', false);
18588 break;
18589 }
18590 break;
18591
18592 case 'FONT-WEIGHT': // normal bold // Does not support: bolder, lighter, 100..900(step value=100)
18593 switch (strtoupper($v)) {
18594 case 'BOLD':
18595 $this->SetStyle('B', true);
18596 break;
18597 case 'NORMAL':
18598 $this->SetStyle('B', false);
18599 break;
18600 }
18601 break;
18602
18603 case 'FONT-KERNING':
18604 if (strtoupper($v) == 'NORMAL' || (strtoupper($v) == 'AUTO' && $this->useKerning)) {
18605 /* -- OTL -- */
18606 if ($this->CurrentFont['haskernGPOS']) {
18607 if (isset($this->OTLtags['Plus'])) {
18608 $this->OTLtags['Plus'] .= ' kern';
18609 } else {
18610 $this->OTLtags['Plus'] = ' kern';
18611 }
18612 } /* -- END OTL -- */ else { // *OTL*
18613 $this->textvar = ($this->textvar | TextVars::FC_KERNING);
18614 } // *OTL*
18615 } elseif (strtoupper($v) == 'NONE' || (strtoupper($v) == 'AUTO' && !$this->useKerning)) {
18616 if (isset($this->OTLtags['Plus'])) {
18617 $this->OTLtags['Plus'] = str_replace('kern', '', $this->OTLtags['Plus']); // *OTL*
18618 }
18619 if (isset($this->OTLtags['FFPlus'])) {
18620 $this->OTLtags['FFPlus'] = preg_replace('/kern[\d]*/', '', $this->OTLtags['FFPlus']);
18621 }
18622 $this->textvar = ($this->textvar & ~TextVars::FC_KERNING);
18623 }
18624 break;
18625
18626 /* -- OTL -- */
18627 case 'FONT-LANGUAGE-OVERRIDE':
18628 $v = strtoupper($v);
18629 if (strpos($v, 'NORMAL') !== false) {
18630 $this->fontLanguageOverride = '';
18631 } else {
18632 $this->fontLanguageOverride = trim($v);
18633 }
18634 break;
18635
18636
18637 case 'FONT-VARIANT-POSITION':
18638 if (isset($this->OTLtags['Plus'])) {
18639 $this->OTLtags['Plus'] = str_replace(['sups', 'subs'], '', $this->OTLtags['Plus']);
18640 }
18641 switch (strtoupper($v)) {
18642 case 'SUPER':
18643 $this->OTLtags['Plus'] .= ' sups';
18644 break;
18645 case 'SUB':
18646 $this->OTLtags['Plus'] .= ' subs';
18647 break;
18648 case 'NORMAL':
18649 break;
18650 }
18651 break;
18652
18653 case 'FONT-VARIANT-CAPS':
18654 $v = strtoupper($v);
18655 if (!isset($this->OTLtags['Plus'])) {
18656 $this->OTLtags['Plus'] = '';
18657 }
18658 $this->OTLtags['Plus'] = str_replace(['c2sc', 'smcp', 'c2pc', 'pcap', 'unic', 'titl'], '', $this->OTLtags['Plus']);
18659 $this->textvar = ($this->textvar & ~TextVars::FC_SMALLCAPS); // ?????????????? <small-caps>
18660 if (strpos($v, 'ALL-SMALL-CAPS') !== false) {
18661 $this->OTLtags['Plus'] .= ' c2sc smcp';
18662 } elseif (strpos($v, 'SMALL-CAPS') !== false) {
18663 if (isset($this->CurrentFont['hassmallcapsGSUB']) && $this->CurrentFont['hassmallcapsGSUB']) {
18664 $this->OTLtags['Plus'] .= ' smcp';
18665 } else {
18666 $this->textvar = ($this->textvar | TextVars::FC_SMALLCAPS);
18667 }
18668 } elseif (strpos($v, 'ALL-PETITE-CAPS') !== false) {
18669 $this->OTLtags['Plus'] .= ' c2pc pcap';
18670 } elseif (strpos($v, 'PETITE-CAPS') !== false) {
18671 $this->OTLtags['Plus'] .= ' pcap';
18672 } elseif (strpos($v, 'UNICASE') !== false) {
18673 $this->OTLtags['Plus'] .= ' unic';
18674 } elseif (strpos($v, 'TITLING-CAPS') !== false) {
18675 $this->OTLtags['Plus'] .= ' titl';
18676 }
18677 break;
18678
18679 case 'FONT-VARIANT-LIGATURES':
18680 $v = strtoupper($v);
18681 if (!isset($this->OTLtags['Plus'])) {
18682 $this->OTLtags['Plus'] = '';
18683 }
18684 if (!isset($this->OTLtags['Minus'])) {
18685 $this->OTLtags['Minus'] = '';
18686 }
18687 if (strpos($v, 'NORMAL') !== false) {
18688 $this->OTLtags['Minus'] = str_replace(['liga', 'clig', 'calt'], '', $this->OTLtags['Minus']);
18689 $this->OTLtags['Plus'] = str_replace(['dlig', 'hlig'], '', $this->OTLtags['Plus']);
18690 } elseif (strpos($v, 'NONE') !== false) {
18691 $this->OTLtags['Minus'] .= ' liga clig calt';
18692 $this->OTLtags['Plus'] = str_replace(['dlig', 'hlig'], '', $this->OTLtags['Plus']);
18693 }
18694 if (strpos($v, 'NO-COMMON-LIGATURES') !== false) {
18695 $this->OTLtags['Minus'] .= ' liga clig';
18696 } elseif (strpos($v, 'COMMON-LIGATURES') !== false) {
18697 $this->OTLtags['Minus'] = str_replace(['liga', 'clig'], '', $this->OTLtags['Minus']);
18698 }
18699 if (strpos($v, 'NO-CONTEXTUAL') !== false) {
18700 $this->OTLtags['Minus'] .= ' calt';
18701 } elseif (strpos($v, 'CONTEXTUAL') !== false) {
18702 $this->OTLtags['Minus'] = str_replace('calt', '', $this->OTLtags['Minus']);
18703 }
18704 if (strpos($v, 'NO-DISCRETIONARY-LIGATURES') !== false) {
18705 $this->OTLtags['Plus'] = str_replace('dlig', '', $this->OTLtags['Plus']);
18706 } elseif (strpos($v, 'DISCRETIONARY-LIGATURES') !== false) {
18707 $this->OTLtags['Plus'] .= ' dlig';
18708 }
18709 if (strpos($v, 'NO-HISTORICAL-LIGATURES') !== false) {
18710 $this->OTLtags['Plus'] = str_replace('hlig', '', $this->OTLtags['Plus']);
18711 } elseif (strpos($v, 'HISTORICAL-LIGATURES') !== false) {
18712 $this->OTLtags['Plus'] .= ' hlig';
18713 }
18714
18715 break;
18716
18717 case 'FONT-VARIANT-NUMERIC':
18718 $v = strtoupper($v);
18719 if (!isset($this->OTLtags['Plus'])) {
18720 $this->OTLtags['Plus'] = '';
18721 }
18722 if (strpos($v, 'NORMAL') !== false) {
18723 $this->OTLtags['Plus'] = str_replace(['ordn', 'zero', 'lnum', 'onum', 'pnum', 'tnum', 'frac', 'afrc'], '', $this->OTLtags['Plus']);
18724 }
18725 if (strpos($v, 'ORDINAL') !== false) {
18726 $this->OTLtags['Plus'] .= ' ordn';
18727 }
18728 if (strpos($v, 'SLASHED-ZERO') !== false) {
18729 $this->OTLtags['Plus'] .= ' zero';
18730 }
18731 if (strpos($v, 'LINING-NUMS') !== false) {
18732 $this->OTLtags['Plus'] .= ' lnum';
18733 $this->OTLtags['Plus'] = str_replace('onum', '', $this->OTLtags['Plus']);
18734 } elseif (strpos($v, 'OLDSTYLE-NUMS') !== false) {
18735 $this->OTLtags['Plus'] .= ' onum';
18736 $this->OTLtags['Plus'] = str_replace('lnum', '', $this->OTLtags['Plus']);
18737 }
18738 if (strpos($v, 'PROPORTIONAL-NUMS') !== false) {
18739 $this->OTLtags['Plus'] .= ' pnum';
18740 $this->OTLtags['Plus'] = str_replace('tnum', '', $this->OTLtags['Plus']);
18741 } elseif (strpos($v, 'TABULAR-NUMS') !== false) {
18742 $this->OTLtags['Plus'] .= ' tnum';
18743 $this->OTLtags['Plus'] = str_replace('pnum', '', $this->OTLtags['Plus']);
18744 }
18745 if (strpos($v, 'DIAGONAL-FRACTIONS') !== false) {
18746 $this->OTLtags['Plus'] .= ' frac';
18747 $this->OTLtags['Plus'] = str_replace('afrc', '', $this->OTLtags['Plus']);
18748 } elseif (strpos($v, 'STACKED-FRACTIONS') !== false) {
18749 $this->OTLtags['Plus'] .= ' afrc';
18750 $this->OTLtags['Plus'] = str_replace('frac', '', $this->OTLtags['Plus']);
18751 }
18752 break;
18753
18754 case 'FONT-VARIANT-ALTERNATES': // Only supports historical-forms
18755 $v = strtoupper($v);
18756 if (!isset($this->OTLtags['Plus'])) {
18757 $this->OTLtags['Plus'] = '';
18758 }
18759 if (strpos($v, 'NORMAL') !== false) {
18760 $this->OTLtags['Plus'] = str_replace('hist', '', $this->OTLtags['Plus']);
18761 }
18762 if (strpos($v, 'HISTORICAL-FORMS') !== false) {
18763 $this->OTLtags['Plus'] .= ' hist';
18764 }
18765 break;
18766
18767
18768 case 'FONT-FEATURE-SETTINGS':
18769 $v = strtolower($v);
18770 if (strpos($v, 'normal') !== false) {
18771 $this->OTLtags['FFMinus'] = '';
18772 $this->OTLtags['FFPlus'] = '';
18773 } else {
18774 if (!isset($this->OTLtags['FFPlus'])) {
18775 $this->OTLtags['FFPlus'] = '';
18776 }
18777 if (!isset($this->OTLtags['FFMinus'])) {
18778 $this->OTLtags['FFMinus'] = '';
18779 }
18780 $tags = preg_split('/[,]/', $v);
18781 foreach ($tags as $t) {
18782 if (preg_match('/[\"\']([a-zA-Z0-9]{4})[\"\']\s*(on|off|\d*){0,1}/', $t, $m)) {
18783 if ($m[2] == 'off' || $m[2] === '0') {
18784 if (strpos($this->OTLtags['FFMinus'], $m[1]) === false) {
18785 $this->OTLtags['FFMinus'] .= ' ' . $m[1];
18786 }
18787 $this->OTLtags['FFPlus'] = preg_replace('/' . $m[1] . '[\d]*/', '', $this->OTLtags['FFPlus']);
18788 } else {
18789 if ($m[2] == 'on') {
18790 $m[2] = '1';
18791 }
18792 if (strpos($this->OTLtags['FFPlus'], $m[1]) === false) {
18793 $this->OTLtags['FFPlus'] .= ' ' . $m[1] . $m[2];
18794 }
18795 $this->OTLtags['FFMinus'] = str_replace($m[1], '', $this->OTLtags['FFMinus']);
18796 }
18797 }
18798 }
18799 }
18800 break;
18801 /* -- END OTL -- */
18802
18803
18804 case 'TEXT-TRANSFORM': // none uppercase lowercase // Does support: capitalize
18805 switch (strtoupper($v)) { // Not working 100%
18806 case 'CAPITALIZE':
18807 $this->textvar = ($this->textvar | TextVars::FT_CAPITALIZE); // mPDF 5.7.1
18808 $this->textvar = ($this->textvar & ~TextVars::FT_UPPERCASE); // mPDF 5.7.1
18809 $this->textvar = ($this->textvar & ~TextVars::FT_LOWERCASE); // mPDF 5.7.1
18810 break;
18811 case 'UPPERCASE':
18812 $this->textvar = ($this->textvar | TextVars::FT_UPPERCASE); // mPDF 5.7.1
18813 $this->textvar = ($this->textvar & ~TextVars::FT_LOWERCASE); // mPDF 5.7.1
18814 $this->textvar = ($this->textvar & ~TextVars::FT_CAPITALIZE); // mPDF 5.7.1
18815 break;
18816 case 'LOWERCASE':
18817 $this->textvar = ($this->textvar | TextVars::FT_LOWERCASE); // mPDF 5.7.1
18818 $this->textvar = ($this->textvar & ~TextVars::FT_UPPERCASE); // mPDF 5.7.1
18819 $this->textvar = ($this->textvar & ~TextVars::FT_CAPITALIZE); // mPDF 5.7.1
18820 break;
18821 case 'NONE':
18822 break;
18823 $this->textvar = ($this->textvar & ~TextVars::FT_UPPERCASE); // mPDF 5.7.1
18824 $this->textvar = ($this->textvar & ~TextVars::FT_LOWERCASE); // mPDF 5.7.1
18825 $this->textvar = ($this->textvar & ~TextVars::FT_CAPITALIZE); // mPDF 5.7.1
18826 }
18827 break;
18828
18829 case 'TEXT-SHADOW':
18830 $ts = $this->cssManager->setCSStextshadow($v);
18831 if ($ts) {
18832 $this->textshadow = $ts;
18833 }
18834 break;
18835
18836 case 'HYPHENS':
18837 if (strtoupper($v) == 'NONE') {
18838 $this->textparam['hyphens'] = 2;
18839 } elseif (strtoupper($v) == 'AUTO') {
18840 $this->textparam['hyphens'] = 1;
18841 } elseif (strtoupper($v) == 'MANUAL') {
18842 $this->textparam['hyphens'] = 0;
18843 }
18844 break;
18845
18846 case 'TEXT-OUTLINE':
18847 if (strtoupper($v) == 'NONE') {
18848 $this->textparam['outline-s'] = false;
18849 }
18850 break;
18851
18852 case 'TEXT-OUTLINE-WIDTH':
18853 case 'OUTLINE-WIDTH':
18854 switch (strtoupper($v)) {
18855 case 'THIN':
18856 $v = '0.03em';
18857 break;
18858 case 'MEDIUM':
18859 $v = '0.05em';
18860 break;
18861 case 'THICK':
18862 $v = '0.07em';
18863 break;
18864 }
18865 $w = $this->sizeConverter->convert($v, $this->FontSize, $this->FontSize);
18866 if ($w) {
18867 $this->textparam['outline-WIDTH'] = $w;
18868 $this->textparam['outline-s'] = true;
18869 } else {
18870 $this->textparam['outline-s'] = false;
18871 }
18872 break;
18873
18874 case 'TEXT-OUTLINE-COLOR':
18875 case 'OUTLINE-COLOR':
18876 if (strtoupper($v) == 'INVERT') {
18877 if ($this->colorarray) {
18878 $cor = $this->colorarray;
18879 $this->textparam['outline-COLOR'] = $this->colorConverter->invert($cor);
18880 } else {
18881 $this->textparam['outline-COLOR'] = $this->colorConverter->convert(255, $this->PDFAXwarnings);
18882 }
18883 } else {
18884 $cor = $this->colorConverter->convert($v, $this->PDFAXwarnings);
18885 if ($cor) {
18886 $this->textparam['outline-COLOR'] = $cor;
18887 }
18888 }
18889 break;
18890
18891 case 'COLOR': // font color
18892 $cor = $this->colorConverter->convert($v, $this->PDFAXwarnings);
18893 if ($cor) {
18894 $this->colorarray = $cor;
18895 $this->SetTColor($cor);
18896 }
18897 break;
18898 }//end of switch($k)
18899 }//end of foreach
18900 // mPDF 5.7.3 inline text-decoration parameters
18901 // Needs to be set at the end - after vertical-align = super/sub, so that textparam['text-baseline'] is set
18902 if (isset($arrayaux['TEXT-DECORATION'])) {
18903 $v = $arrayaux['TEXT-DECORATION']; // none underline line-through (strikeout) // Does not support: blink
18904 if (stristr($v, 'LINE-THROUGH')) {
18905 $this->textvar = ($this->textvar | TextVars::FD_LINETHROUGH);
18906 // mPDF 5.7.3 inline text-decoration parameters
18907 if (isset($this->textparam['text-baseline'])) {
18908 $this->textparam['s-decoration']['baseline'] = $this->textparam['text-baseline'];
18909 } else {
18910 $this->textparam['s-decoration']['baseline'] = 0;
18911 }
18912 $this->textparam['s-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
18913 $this->textparam['s-decoration']['fontsize'] = $this->FontSize;
18914 $this->textparam['s-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
18915 }
18916 if (stristr($v, 'UNDERLINE')) {
18917 $this->textvar = ($this->textvar | TextVars::FD_UNDERLINE);
18918 // mPDF 5.7.3 inline text-decoration parameters
18919 if (isset($this->textparam['text-baseline'])) {
18920 $this->textparam['u-decoration']['baseline'] = $this->textparam['text-baseline'];
18921 } else {
18922 $this->textparam['u-decoration']['baseline'] = 0;
18923 }
18924 $this->textparam['u-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
18925 $this->textparam['u-decoration']['fontsize'] = $this->FontSize;
18926 $this->textparam['u-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
18927 }
18928 if (stristr($v, 'OVERLINE')) {
18929 $this->textvar = ($this->textvar | TextVars::FD_OVERLINE);
18930 // mPDF 5.7.3 inline text-decoration parameters
18931 if (isset($this->textparam['text-baseline'])) {
18932 $this->textparam['o-decoration']['baseline'] = $this->textparam['text-baseline'];
18933 } else {
18934 $this->textparam['o-decoration']['baseline'] = 0;
18935 }
18936 $this->textparam['o-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
18937 $this->textparam['o-decoration']['fontsize'] = $this->FontSize;
18938 $this->textparam['o-decoration']['color'] = strtoupper($this->TextColor); // change 0 0 0 rg to 0 0 0 RG
18939 }
18940 if (stristr($v, 'NONE')) {
18941 $this->textvar = ($this->textvar & ~TextVars::FD_UNDERLINE);
18942 $this->textvar = ($this->textvar & ~TextVars::FD_LINETHROUGH);
18943 $this->textvar = ($this->textvar & ~TextVars::FD_OVERLINE);
18944 // mPDF 5.7.3 inline text-decoration parameters
18945 if (isset($this->textparam['u-decoration'])) {
18946 unset($this->textparam['u-decoration']);
18947 }
18948 if (isset($this->textparam['s-decoration'])) {
18949 unset($this->textparam['s-decoration']);
18950 }
18951 if (isset($this->textparam['o-decoration'])) {
18952 unset($this->textparam['o-decoration']);
18953 }
18954 }
18955 }
18956 // mPDF 6
18957 if ($spanbordset) { // BORDER has been set on this INLINE element
18958 if (isset($this->textparam['text-baseline'])) {
18959 $this->textparam['bord-decoration']['baseline'] = $this->textparam['text-baseline'];
18960 } else {
18961 $this->textparam['bord-decoration']['baseline'] = 0;
18962 }
18963 $this->textparam['bord-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
18964 $this->textparam['bord-decoration']['fontsize'] = $this->FontSize;
18965 }
18966 if ($spanbgset) { // BACKGROUND[-COLOR] has been set on this INLINE element
18967 if (isset($this->textparam['text-baseline'])) {
18968 $this->textparam['bg-decoration']['baseline'] = $this->textparam['text-baseline'];
18969 } else {
18970 $this->textparam['bg-decoration']['baseline'] = 0;
18971 }
18972 $this->textparam['bg-decoration']['fontkey'] = $this->FontFamily . $this->FontStyle;
18973 $this->textparam['bg-decoration']['fontsize'] = $this->FontSize;
18974 }
18975 }
18976
18977 /* -- END HTML-CSS -- */
18978
18979 function SetStyle($tag, $enable)
18980 {
18981 $this->$tag = $enable;
18982 $style = '';
18983 foreach (['B', 'I'] as $s) {
18984 if ($this->$s) {
18985 $style .= $s;
18986 }
18987 }
18988 $this->currentfontstyle = $style;
18989 $this->SetFont('', $style, 0, false);
18990 }
18991
18992 // Set multiple styles at one time
18993 function SetStylesArray($arr)
18994 {
18995 $style = '';
18996 foreach (['B', 'I'] as $s) {
18997 if (isset($arr[$s])) {
18998 if ($arr[$s]) {
18999 $this->$s = true;
19000 $style .= $s;
19001 } else {
19002 $this->$s = false;
19003 }
19004 } elseif ($this->$s) {
19005 $style .= $s;
19006 }
19007 }
19008 $this->currentfontstyle = $style;
19009 $this->SetFont('', $style, 0, false);
19010 }
19011
19012 // Set multiple styles at one $str e.g. "BI"
19013 function SetStyles($str)
19014 {
19015 $style = '';
19016 foreach (['B', 'I'] as $s) {
19017 if (strpos($str, $s) !== false) {
19018 $this->$s = true;
19019 $style .= $s;
19020 } else {
19021 $this->$s = false;
19022 }
19023 }
19024 $this->currentfontstyle = $style;
19025 $this->SetFont('', $style, 0, false);
19026 }
19027
19028 function ResetStyles()
19029 {
19030 foreach (['B', 'I'] as $s) {
19031 $this->$s = false;
19032 }
19033 $this->currentfontstyle = '';
19034 $this->SetFont('', '', 0, false);
19035 }
19036
19037 function DisableTags($str = '')
19038 {
19039 if ($str == '') { // enable all tags
19040 // Insert new supported tags in the long string below.
19041 $this->enabledtags = "<a><acronym><address><article><aside><b><bdi><bdo><big><blockquote><br><caption><center><cite><code><del><details><dd><div><dl><dt><em><fieldset><figcaption><figure><font><form><h1><h2><h3><h4><h5><h6><hgroup><hr><i><img><input><ins><kbd><legend><li><main><mark><meter><nav><ol><option><p><pre><progress><q><s><samp><section><select><small><span><strike><strong><sub><summary><sup><table><tbody><td><template><textarea><tfoot><th><thead><time><tr><tt><u><ul><var><footer><header><annotation><bookmark><textcircle><barcode><dottab><indexentry><indexinsert><watermarktext><watermarkimage><tts><ttz><tta><column_break><columnbreak><newcolumn><newpage><page_break><pagebreak><formfeed><columns><toc><tocentry><tocpagebreak><pageheader><pagefooter><setpageheader><setpagefooter><sethtmlpageheader><sethtmlpagefooter>";
19042 } else {
19043 $str = explode(",", $str);
19044 foreach ($str as $v) {
19045 $this->enabledtags = str_replace(trim($v), '', $this->enabledtags);
19046 }
19047 }
19048 }
19049
19050 /* -- TABLES -- */
19051
19052 function TableCheckMinWidth($maxwidth, $forcewrap = 0, $textbuffer = [], $checkletter = false)
19053 {
19054 // mPDF 6
19055 $acclength = 0; // mPDF 6 (accumulated length across > 1 chunk)
19056 $acclongest = 0; // mPDF 6 (accumulated length max across > 1 chunk)
19057 $biggestword = 0;
19058 $toonarrow = false;
19059 if ((count($textbuffer) == 0) or ( (count($textbuffer) == 1) && ($textbuffer[0][0] == ''))) {
19060 return 0;
19061 }
19062
19063 foreach ($textbuffer as $chunk) {
19064 $line = $chunk[0];
19065 $OTLdata = (isset($chunk[18]) ? $chunk[18] : null);
19066
19067 // mPDF ITERATION
19068 if ($this->iterationCounter) {
19069 $line = preg_replace('/{iteration ([a-zA-Z0-9_]+)}/', '\\1', $line);
19070 }
19071
19072 // IMAGES & FORM ELEMENTS
19073 if (substr($line, 0, 3) == "\xbb\xa4\xac") { // inline object - FORM element or IMAGE!
19074 $objattr = $this->_getObjAttr($line);
19075 if ($objattr['type'] != 'hr' && isset($objattr['width']) && ($objattr['width'] / $this->shrin_k) > ($maxwidth + 0.0001)) {
19076 if (($objattr['width'] / $this->shrin_k) > $biggestword) {
19077 $biggestword = ($objattr['width'] / $this->shrin_k);
19078 }
19079 $toonarrow = true;
19080 }
19081 continue;
19082 }
19083
19084 if ($line == "\n") {
19085 $acclength = 0; // mPDF 6 (accumulated length across > 1 chunk)
19086 continue;
19087 }
19088 $line = trim($line);
19089 if (!empty($OTLdata)) {
19090 $this->otl->trimOTLdata($OTLdata, true, true);
19091 } // *OTL*
19092 // SET FONT SIZE/STYLE from $chunk[n]
19093 // FONTSIZE
19094 if (isset($chunk[11]) and $chunk[11] != '') {
19095 if ($this->shrin_k) {
19096 $this->SetFontSize($chunk[11] / $this->shrin_k, false);
19097 } else {
19098 $this->SetFontSize($chunk[11], false);
19099 }
19100 }
19101 // FONTFAMILY
19102 if (isset($chunk[4]) and $chunk[4] != '') {
19103 $font = $this->SetFont($chunk[4], $this->FontStyle, 0, false);
19104 }
19105 // B I
19106 if (isset($chunk[2]) and $chunk[2] != '') {
19107 $this->SetStyles($chunk[2]);
19108 }
19109
19110 $lbw = $rbw = 0; // Border widths
19111 if (isset($chunk[16]) && !empty($chunk[16])) { // Border
19112 $this->spanborddet = $chunk[16];
19113 $lbw = (isset($this->spanborddet['L']['w']) ? $this->spanborddet['L']['w'] : 0);
19114 $rbw = (isset($this->spanborddet['R']['w']) ? $this->spanborddet['R']['w'] : 0);
19115 }
19116 if (isset($chunk[15])) { // Word spacing
19117 $this->wSpacingCSS = $chunk[15];
19118 if ($this->wSpacingCSS && strtoupper($this->wSpacingCSS) != 'NORMAL') {
19119 $this->minwSpacing = $this->sizeConverter->convert($this->wSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
19120 }
19121 }
19122 if (isset($chunk[14])) { // Letter spacing
19123 $this->lSpacingCSS = $chunk[14];
19124 if (($this->lSpacingCSS || $this->lSpacingCSS === '0') && strtoupper($this->lSpacingCSS) != 'NORMAL') {
19125 $this->fixedlSpacing = $this->sizeConverter->convert($this->lSpacingCSS, $this->FontSize) / $this->shrin_k; // mPDF 5.7.3
19126 }
19127 }
19128 if (isset($chunk[8])) { // mPDF 5.7.1
19129 $this->textvar = $chunk[8];
19130 }
19131
19132 // mPDF 6
19133 // If overflow==wrap ($checkletter) OR (No word breaks and contains CJK)
19134 if ($checkletter || (!preg_match('/(\xe2\x80\x8b| )/', trim($line)) && preg_match("/([" . $this->pregCJKchars . "])/u", $line) )) {
19135 if (preg_match("/([" . $this->pregCJKchars . "])/u", $line)) {
19136 $checkCJK = true;
19137 } else {
19138 $checkCJK = false;
19139 }
19140
19141 $letters = preg_split('//u', $line);
19142 foreach ($letters as $k => $letter) {
19143 // mPDF 6
19144 if ($checkCJK) {
19145 if (preg_match("/[" . $this->CJKleading . "]/u", $letter) && $k > 0) {
19146 $letter = $letters[$k - 1] . $letter;
19147 }
19148 if (preg_match("/[" . $this->CJKfollowing . "]/u", $letter) && $k < (count($letters) - 1)) {
19149 $letter = $letter . $letters[$k + 1];
19150 }
19151 }
19152
19153 $letterwidth = $this->GetStringWidth($letter, false, false, $chunk[8]); // Pass $textvar ($chunk[8]), but do OTLdata here
19154 // so don't have to split OTLdata for each word
19155 if ($k == 0) {
19156 $letterwidth += $lbw;
19157 }
19158 if ($k == (count($letters) - 1)) {
19159 $letterwidth += $rbw;
19160 }
19161
19162 // Warn user that maxwidth is insufficient
19163 if ($letterwidth > $maxwidth + 0.0001) {
19164 if ($letterwidth > $biggestword) {
19165 $biggestword = $letterwidth;
19166 }
19167 $toonarrow = true;
19168 }
19169 }
19170 } else {
19171 // mPDF 6
19172 // Need to account for any XAdvance in GPOSinfo (OTLdata = $chunk[18])
19173 $wordXAdvance = [];
19174 if (isset($chunk[18]) && $chunk[18]) {
19175 preg_match_all('/(\xe2\x80\x8b| )/', $line, $spaces, PREG_OFFSET_CAPTURE); // U+200B Zero Width word boundary, or space
19176 $lastoffset = 0;
19177 $k = -1; // Added so that if no spaces found, "last word" later is calculated for the one and only word
19178 foreach ($spaces[0] as $k => $m) {
19179 $offset = $m[1];
19180 // ...TableCheckMinWidth...
19181 // At this point, BIDI not applied, Writing direction is not set, and XAdvanceL balances XAdvanceR
19182 for ($n = $lastoffset; $n < $offset; $n++) {
19183 if (isset($chunk[18]['GPOSinfo'][$n]['XAdvanceL'])) {
19184 if (isset($wordXAdvance[$k])) {
19185 $wordXAdvance[$k] += $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
19186 } else {
19187 $wordXAdvance[$k] = $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
19188 }
19189 }
19190 }
19191 $lastoffset = $offset + 1;
19192 }
19193
19194 $k++; // last word
19195 foreach ($chunk[18]['GPOSinfo'] as $n => $gpos) {
19196 if ($n >= $lastoffset && isset($chunk[18]['GPOSinfo'][$n]['XAdvanceL'])) {
19197 if (isset($wordXAdvance[$k])) {
19198 $wordXAdvance[$k] += $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
19199 } else {
19200 $wordXAdvance[$k] = $chunk[18]['GPOSinfo'][$n]['XAdvanceL'];
19201 }
19202 }
19203 }
19204 }
19205
19206 $words = preg_split('/(\xe2\x80\x8b| )/', $line); // U+200B Zero Width word boundary, or space
19207 foreach ($words as $k => $word) {
19208 $word = trim($word);
19209 $wordwidth = $this->GetStringWidth($word, false, false, $chunk[8]); // Pass $textvar ($chunk[8]), but do OTLdata here
19210 // so don't have to split OTLdata for each word
19211 if (isset($wordXAdvance[$k])) {
19212 $wordwidth += ($wordXAdvance[$k] * 1000 / $this->CurrentFont['unitsPerEm']) * ($this->FontSize / 1000);
19213 }
19214 if ($k == 0) {
19215 $wordwidth += $lbw;
19216 }
19217 if ($k == (count($words) - 1)) {
19218 $wordwidth += $rbw;
19219 }
19220
19221 // mPDF 6
19222 if (count($words) == 1 && substr($chunk[0], 0, 1) != ' ') {
19223 $acclength += $wordwidth;
19224 } elseif (count($words) > 1 && $k == 0 && substr($chunk[0], 0, 1) != ' ') {
19225 $acclength += $wordwidth;
19226 } else {
19227 $acclength = $wordwidth;
19228 }
19229 $acclongest = max($acclongest, $acclength);
19230 if (count($words) == 1 && substr($chunk[0], -1, 1) == ' ') {
19231 $acclength = 0;
19232 } elseif (count($words) > 1 && ($k != (count($words) - 1) || substr($chunk[0], -1, 1) == ' ')) {
19233 $acclength = 0;
19234 }
19235
19236 // Warn user that maxwidth is insufficient
19237 if ($wordwidth > $maxwidth + 0.0001) {
19238 if ($wordwidth > $biggestword) {
19239 $biggestword = $wordwidth;
19240 }
19241 $toonarrow = true;
19242 }
19243 }
19244 }
19245
19246 // mPDF 6 Accumulated length of biggest word - across multiple chunks
19247 if ($acclongest > $maxwidth + 0.0001) {
19248 if ($acclongest > $biggestword) {
19249 $biggestword = $acclongest;
19250 }
19251 $toonarrow = true;
19252 }
19253
19254 // RESET FONT SIZE/STYLE
19255 // RESETTING VALUES
19256 // Now we must deactivate what we have used
19257 if (isset($chunk[2]) and $chunk[2] != '') {
19258 $this->ResetStyles();
19259 }
19260 if (isset($chunk[4]) and $chunk[4] != '') {
19261 $this->SetFont($this->default_font, $this->FontStyle, 0, false);
19262 }
19263 if (isset($chunk[11]) and $chunk[11] != '') {
19264 $this->SetFontSize($this->default_font_size, false);
19265 }
19266 $this->spanborddet = [];
19267 $this->textvar = 0x00; // mPDF 5.7.1
19268 $this->OTLtags = [];
19269 $this->lSpacingCSS = '';
19270 $this->wSpacingCSS = '';
19271 $this->fixedlSpacing = false;
19272 $this->minwSpacing = 0;
19273 }
19274
19275 // Return -(wordsize) if word is bigger than maxwidth
19276 // ADDED
19277 if (($toonarrow) && ($this->table_error_report)) {
19278 throw new \Mpdf\MpdfException("Word is too long to fit in table - " . $this->table_error_report_param);
19279 }
19280 if ($toonarrow) {
19281 return -$biggestword;
19282 } else {
19283 return 1;
19284 }
19285 }
19286
19287 function shrinkTable(&$table, $k)
19288 {
19289 $table['border_spacing_H'] /= $k;
19290 $table['border_spacing_V'] /= $k;
19291
19292 $table['padding']['T'] /= $k;
19293 $table['padding']['R'] /= $k;
19294 $table['padding']['B'] /= $k;
19295 $table['padding']['L'] /= $k;
19296
19297 $table['margin']['T'] /= $k;
19298 $table['margin']['R'] /= $k;
19299 $table['margin']['B'] /= $k;
19300 $table['margin']['L'] /= $k;
19301
19302 $table['border_details']['T']['w'] /= $k;
19303 $table['border_details']['R']['w'] /= $k;
19304 $table['border_details']['B']['w'] /= $k;
19305 $table['border_details']['L']['w'] /= $k;
19306
19307 if (isset($table['max_cell_border_width']['T'])) {
19308 $table['max_cell_border_width']['T'] /= $k;
19309 }
19310 if (isset($table['max_cell_border_width']['R'])) {
19311 $table['max_cell_border_width']['R'] /= $k;
19312 }
19313 if (isset($table['max_cell_border_width']['B'])) {
19314 $table['max_cell_border_width']['B'] /= $k;
19315 }
19316 if (isset($table['max_cell_border_width']['L'])) {
19317 $table['max_cell_border_width']['L'] /= $k;
19318 }
19319
19320 if ($this->simpleTables) {
19321 $table['simple']['border_details']['T']['w'] /= $k;
19322 $table['simple']['border_details']['R']['w'] /= $k;
19323 $table['simple']['border_details']['B']['w'] /= $k;
19324 $table['simple']['border_details']['L']['w'] /= $k;
19325 }
19326
19327 $table['miw'] /= $k;
19328 $table['maw'] /= $k;
19329
19330 for ($j = 0; $j < $table['nc']; $j++) { // columns
19331
19332 $table['wc'][$j]['miw'] = isset($table['wc'][$j]['miw']) ? $table['wc'][$j]['miw'] : 0;
19333 $table['wc'][$j]['maw'] = isset($table['wc'][$j]['maw']) ? $table['wc'][$j]['maw'] : 0;
19334
19335 $table['wc'][$j]['miw'] /= $k;
19336 $table['wc'][$j]['maw'] /= $k;
19337
19338 if (isset($table['decimal_align'][$j]['maxs0']) && $table['decimal_align'][$j]['maxs0']) {
19339 $table['decimal_align'][$j]['maxs0'] /= $k;
19340 }
19341
19342 if (isset($table['decimal_align'][$j]['maxs1']) && $table['decimal_align'][$j]['maxs1']) {
19343 $table['decimal_align'][$j]['maxs1'] /= $k;
19344 }
19345
19346 if (isset($table['wc'][$j]['absmiw']) && $table['wc'][$j]['absmiw']) {
19347 $table['wc'][$j]['absmiw'] /= $k;
19348 }
19349
19350 for ($i = 0; $i < $table['nr']; $i++) { // rows
19351
19352 $c = &$table['cells'][$i][$j];
19353
19354 if (isset($c) && $c) {
19355
19356 if (!$this->simpleTables) {
19357
19358 if ($this->packTableData) {
19359
19360 $cell = $this->_unpackCellBorder($c['borderbin']);
19361
19362 $cell['border_details']['T']['w'] /= $k;
19363 $cell['border_details']['R']['w'] /= $k;
19364 $cell['border_details']['B']['w'] /= $k;
19365 $cell['border_details']['L']['w'] /= $k;
19366 $cell['border_details']['mbw']['TL'] /= $k;
19367 $cell['border_details']['mbw']['TR'] /= $k;
19368 $cell['border_details']['mbw']['BL'] /= $k;
19369 $cell['border_details']['mbw']['BR'] /= $k;
19370 $cell['border_details']['mbw']['LT'] /= $k;
19371 $cell['border_details']['mbw']['LB'] /= $k;
19372 $cell['border_details']['mbw']['RT'] /= $k;
19373 $cell['border_details']['mbw']['RB'] /= $k;
19374
19375 $c['borderbin'] = $this->_packCellBorder($cell);
19376
19377 } else {
19378
19379 $c['border_details']['T']['w'] /= $k;
19380 $c['border_details']['R']['w'] /= $k;
19381 $c['border_details']['B']['w'] /= $k;
19382 $c['border_details']['L']['w'] /= $k;
19383 $c['border_details']['mbw']['TL'] /= $k;
19384 $c['border_details']['mbw']['TR'] /= $k;
19385 $c['border_details']['mbw']['BL'] /= $k;
19386 $c['border_details']['mbw']['BR'] /= $k;
19387 $c['border_details']['mbw']['LT'] /= $k;
19388 $c['border_details']['mbw']['LB'] /= $k;
19389 $c['border_details']['mbw']['RT'] /= $k;
19390 $c['border_details']['mbw']['RB'] /= $k;
19391 }
19392 }
19393
19394 $c['padding']['T'] /= $k;
19395 $c['padding']['R'] /= $k;
19396 $c['padding']['B'] /= $k;
19397 $c['padding']['L'] /= $k;
19398
19399 $c['maxs'] = isset($c['maxs']) ? $c['maxs'] /= $k : null;
19400 $c['w'] = isset($c['w']) ? $c['w'] /= $k : null;
19401
19402 $c['s'] = isset($c['s']) ? $c['s'] /= $k : 0;
19403 $c['h'] = isset($c['h']) ? $c['h'] /= $k : null;
19404
19405 $c['miw'] = isset($c['miw']) ? $c['miw'] /= $k : 0;
19406 $c['maw'] = isset($c['maw']) ? $c['maw'] /= $k : 0;
19407
19408 $c['absmiw'] = isset($c['absmiw']) ? $c['absmiw'] /= $k : null;
19409
19410 $c['nestedmaw'] = isset($c['nestedmaw']) ? $c['nestedmaw'] /= $k : null;
19411 $c['nestedmiw'] = isset($c['nestedmiw']) ? $c['nestedmiw'] /= $k : null;
19412
19413 if (isset($c['textbuffer'])) {
19414 foreach ($c['textbuffer'] as $n => $tb) {
19415 if (!empty($tb[16])) {
19416 !isset($c['textbuffer'][$n][16]['T']) || $c['textbuffer'][$n][16]['T']['w'] /= $k;
19417 !isset($c['textbuffer'][$n][16]['B']) || $c['textbuffer'][$n][16]['B']['w'] /= $k;
19418 !isset($c['textbuffer'][$n][16]['L']) || $c['textbuffer'][$n][16]['L']['w'] /= $k;
19419 !isset($c['textbuffer'][$n][16]['R']) || $c['textbuffer'][$n][16]['R']['w'] /= $k;
19420 }
19421 }
19422 }
19423
19424 unset($c);
19425 }
19426
19427 } // rows
19428 } // columns
19429 }
19430
19431 function read_short(&$fh)
19432 {
19433 $s = fread($fh, 2);
19434 $a = (ord($s[0]) << 8) + ord($s[1]);
19435 if ($a & (1 << 15)) {
19436 $a = ($a - (1 << 16));
19437 }
19438 return $a;
19439 }
19440
19441 function _packCellBorder($cell)
19442 {
19443 if (!is_array($cell) || !isset($cell)) {
19444 return '';
19445 }
19446
19447 if (!$this->packTableData) {
19448 return $cell;
19449 }
19450 // = 186 bytes
19451 $bindata = pack("nnda6A10nnda6A10nnda6A10nnda6A10nd9", $cell['border'], $cell['border_details']['R']['s'], $cell['border_details']['R']['w'], $cell['border_details']['R']['c'], $cell['border_details']['R']['style'], $cell['border_details']['R']['dom'], $cell['border_details']['L']['s'], $cell['border_details']['L']['w'], $cell['border_details']['L']['c'], $cell['border_details']['L']['style'], $cell['border_details']['L']['dom'], $cell['border_details']['T']['s'], $cell['border_details']['T']['w'], $cell['border_details']['T']['c'], $cell['border_details']['T']['style'], $cell['border_details']['T']['dom'], $cell['border_details']['B']['s'], $cell['border_details']['B']['w'], $cell['border_details']['B']['c'], $cell['border_details']['B']['style'], $cell['border_details']['B']['dom'], $cell['border_details']['mbw']['BL'], $cell['border_details']['mbw']['BR'], $cell['border_details']['mbw']['RT'], $cell['border_details']['mbw']['RB'], $cell['border_details']['mbw']['TL'], $cell['border_details']['mbw']['TR'], $cell['border_details']['mbw']['LT'], $cell['border_details']['mbw']['LB'], (isset($cell['border_details']['cellposdom']) ? $cell['border_details']['cellposdom'] : 0));
19452 return $bindata;
19453 }
19454
19455 function _getBorderWidths($bindata)
19456 {
19457 if (!$bindata) {
19458 return [0, 0, 0, 0];
19459 }
19460 if (!$this->packTableData) {
19461 return [$bindata['border_details']['T']['w'], $bindata['border_details']['R']['w'], $bindata['border_details']['B']['w'], $bindata['border_details']['L']['w']];
19462 }
19463
19464 $bd = unpack("nbord/nrs/drw/a6rca/A10rst/nrd/nls/dlw/a6lca/A10lst/nld/nts/dtw/a6tca/A10tst/ntd/nbs/dbw/a6bca/A10bst/nbd/dmbl/dmbr/dmrt/dmrb/dmtl/dmtr/dmlt/dmlb/dcpd", $bindata);
19465 $cell['border_details']['R']['w'] = $bd['rw'];
19466 $cell['border_details']['L']['w'] = $bd['lw'];
19467 $cell['border_details']['T']['w'] = $bd['tw'];
19468 $cell['border_details']['B']['w'] = $bd['bw'];
19469 return [$bd['tw'], $bd['rw'], $bd['bw'], $bd['lw']];
19470 }
19471
19472 function _unpackCellBorder($bindata)
19473 {
19474 if (!$bindata) {
19475 return [];
19476 }
19477 if (!$this->packTableData) {
19478 return $bindata;
19479 }
19480
19481 $bd = unpack("nbord/nrs/drw/a6rca/A10rst/nrd/nls/dlw/a6lca/A10lst/nld/nts/dtw/a6tca/A10tst/ntd/nbs/dbw/a6bca/A10bst/nbd/dmbl/dmbr/dmrt/dmrb/dmtl/dmtr/dmlt/dmlb/dcpd", $bindata);
19482
19483 $cell['border'] = $bd['bord'];
19484 $cell['border_details']['R']['s'] = $bd['rs'];
19485 $cell['border_details']['R']['w'] = $bd['rw'];
19486 $cell['border_details']['R']['c'] = str_pad($bd['rca'], 6, "\x00");
19487 $cell['border_details']['R']['style'] = trim($bd['rst']);
19488 $cell['border_details']['R']['dom'] = $bd['rd'];
19489
19490 $cell['border_details']['L']['s'] = $bd['ls'];
19491 $cell['border_details']['L']['w'] = $bd['lw'];
19492 $cell['border_details']['L']['c'] = str_pad($bd['lca'], 6, "\x00");
19493 $cell['border_details']['L']['style'] = trim($bd['lst']);
19494 $cell['border_details']['L']['dom'] = $bd['ld'];
19495
19496 $cell['border_details']['T']['s'] = $bd['ts'];
19497 $cell['border_details']['T']['w'] = $bd['tw'];
19498 $cell['border_details']['T']['c'] = str_pad($bd['tca'], 6, "\x00");
19499 $cell['border_details']['T']['style'] = trim($bd['tst']);
19500 $cell['border_details']['T']['dom'] = $bd['td'];
19501
19502 $cell['border_details']['B']['s'] = $bd['bs'];
19503 $cell['border_details']['B']['w'] = $bd['bw'];
19504 $cell['border_details']['B']['c'] = str_pad($bd['bca'], 6, "\x00");
19505 $cell['border_details']['B']['style'] = trim($bd['bst']);
19506 $cell['border_details']['B']['dom'] = $bd['bd'];
19507
19508 $cell['border_details']['mbw']['BL'] = $bd['mbl'];
19509 $cell['border_details']['mbw']['BR'] = $bd['mbr'];
19510 $cell['border_details']['mbw']['RT'] = $bd['mrt'];
19511 $cell['border_details']['mbw']['RB'] = $bd['mrb'];
19512 $cell['border_details']['mbw']['TL'] = $bd['mtl'];
19513 $cell['border_details']['mbw']['TR'] = $bd['mtr'];
19514 $cell['border_details']['mbw']['LT'] = $bd['mlt'];
19515 $cell['border_details']['mbw']['LB'] = $bd['mlb'];
19516 $cell['border_details']['cellposdom'] = $bd['cpd'];
19517
19518
19519 return($cell);
19520 }
19521
19525 // table Array of (w, h, bc, nr, wc, hr, cells)
19526 // w Width of table
19527 // h Height of table
19528 // nc Number column
19529 // nr Number row
19530 // hr List of height of each row
19531 // wc List of width of each column
19532 // cells List of cells of each rows, cells[i][j] is a cell in the table
19533 function _tableColumnWidth(&$table, $firstpass = false)
19534 {
19535 $cs = &$table['cells'];
19536
19537 $nc = $table['nc'];
19538 $nr = $table['nr'];
19539 $listspan = [];
19540
19541 if ($table['borders_separate']) {
19542 $tblbw = $table['border_details']['L']['w'] + $table['border_details']['R']['w'] + $table['margin']['L'] + $table['margin']['R'] + $table['padding']['L'] + $table['padding']['R'] + $table['border_spacing_H'];
19543 } else {
19544 $tblbw = $table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2 + $table['margin']['L'] + $table['margin']['R'];
19545 }
19546
19547 // ADDED table['l'][colno]
19548 // = total length of text approx (using $c['s']) in that column - used to approximately distribute col widths in _tableWidth
19549 //
19550 for ($j = 0; $j < $nc; $j++) { // columns
19551 $wc = &$table['wc'][$j];
19552 for ($i = 0; $i < $nr; $i++) { // rows
19553 if (isset($cs[$i][$j]) && $cs[$i][$j]) {
19554 $c = &$cs[$i][$j];
19555
19556 if ($this->simpleTables) {
19557 if ($table['borders_separate']) { // NB twice border width
19558 $extrcw = $table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w'] + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
19559 } else {
19560 $extrcw = $table['simple']['border_details']['L']['w'] / 2 + $table['simple']['border_details']['R']['w'] / 2 + $c['padding']['L'] + $c['padding']['R'];
19561 }
19562 } else {
19563 if ($this->packTableData) {
19564 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
19565 } else {
19566 $br = $c['border_details']['R']['w'];
19567 $bl = $c['border_details']['L']['w'];
19568 }
19569 if ($table['borders_separate']) { // NB twice border width
19570 $extrcw = $bl + $br + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
19571 } else {
19572 $extrcw = $bl / 2 + $br / 2 + $c['padding']['L'] + $c['padding']['R'];
19573 }
19574 }
19575
19576 // $mw = $this->GetStringWidth('W') + $extrcw ;
19577 $mw = $extrcw; // mPDF 6
19578 if (substr($c['a'], 0, 1) == 'D') {
19579 $mw = $table['decimal_align'][$j]['maxs0'] + $table['decimal_align'][$j]['maxs1'] + $extrcw;
19580 }
19581
19582 $c['absmiw'] = $mw;
19583
19584 if (isset($c['R']) && $c['R']) {
19585 $c['maw'] = $c['miw'] = $this->FontSize + $extrcw;
19586 if (isset($c['w'])) { // If cell width is specified
19587 if ($c['miw'] < $c['w']) {
19588 $c['miw'] = $c['w'];
19589 }
19590 }
19591 if (!isset($c['colspan'])) {
19592 if ($wc['miw'] < $c['miw']) {
19593 $wc['miw'] = $c['miw'];
19594 }
19595 if ($wc['maw'] < $c['maw']) {
19596 $wc['maw'] = $c['maw'];
19597 }
19598
19599 if ($firstpass) {
19600 if (isset($table['l'][$j])) {
19601 $table['l'][$j] += $c['miw'];
19602 } else {
19603 $table['l'][$j] = $c['miw'];
19604 }
19605 }
19606 }
19607 if ($c['miw'] > $wc['miw']) {
19608 $wc['miw'] = $c['miw'];
19609 }
19610 if ($wc['miw'] > $wc['maw']) {
19611 $wc['maw'] = $wc['miw'];
19612 }
19613 continue;
19614 }
19615
19616 if ($firstpass) {
19617 if (isset($c['s'])) {
19618 $c['s'] += $extrcw;
19619 }
19620 if (isset($c['maxs'])) {
19621 $c['maxs'] += $extrcw;
19622 }
19623 if (isset($c['nestedmiw'])) {
19624 $c['nestedmiw'] += $extrcw;
19625 }
19626 if (isset($c['nestedmaw'])) {
19627 $c['nestedmaw'] += $extrcw;
19628 }
19629 }
19630
19631
19632 // If minimum width has already been set by a nested table or inline object (image/form), use it
19633 if (isset($c['nestedmiw']) && (!isset($this->table[1][1]['overflow']) || $this->table[1][1]['overflow'] != 'visible')) {
19634 $miw = $c['nestedmiw'];
19635 } else {
19636 $miw = $mw;
19637 }
19638
19639 if (isset($c['maxs']) && $c['maxs'] != '') {
19640 $c['s'] = $c['maxs'];
19641 }
19642
19643 // If maximum width has already been set by a nested table, use it
19644 if (isset($c['nestedmaw'])) {
19645 $c['maw'] = $c['nestedmaw'];
19646 } else {
19647 $c['maw'] = $c['s'];
19648 }
19649
19650 if (isset($table['overflow']) && $table['overflow'] == 'visible' && $table['level'] == 1) {
19651 if (($c['maw'] + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
19652 $c['maw'] = $this->blk[$this->blklvl]['inner_width'] - $tblbw;
19653 }
19654 }
19655
19656 if (isset($c['nowrap']) && $c['nowrap']) {
19657 $miw = $c['maw'];
19658 }
19659
19660 if (isset($c['wpercent']) && $firstpass) {
19661 if (isset($c['colspan'])) { // Not perfect - but % set on colspan is shared equally on cols.
19662 for ($k = 0; $k < $c['colspan']; $k++) {
19663 $table['wc'][($j + $k)]['wpercent'] = $c['wpercent'] / $c['colspan'];
19664 }
19665 } else {
19666 if (isset($table['w']) && $table['w']) {
19667 $c['w'] = $c['wpercent'] / 100 * ($table['w'] - $tblbw );
19668 }
19669 $wc['wpercent'] = $c['wpercent'];
19670 }
19671 }
19672
19673 if (isset($table['overflow']) && $table['overflow'] == 'visible' && $table['level'] == 1) {
19674 if (isset($c['w']) && ($c['w'] + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
19675 $c['w'] = $this->blk[$this->blklvl]['inner_width'] - $tblbw;
19676 }
19677 }
19678
19679
19680 if (isset($c['w'])) { // If cell width is specified
19681 if ($miw < $c['w']) {
19682 $c['miw'] = $c['w'];
19683 } // Cell min width = that specified
19684 if ($miw > $c['w']) {
19685 $c['miw'] = $c['w'] = $miw;
19686 } // If width specified is less than minimum allowed (W) increase it
19687 // mPDF 5.7.4 Do not set column width in colspan
19688 // cf. http://www.mpdf1.com/forum/discussion/2221/colspan-bug
19689 if (!isset($c['colspan'])) {
19690 if (!isset($wc['w'])) {
19691 $wc['w'] = 1;
19692 } // If the Col width is not specified = set it to 1
19693 }
19694 // mPDF 5.7.3 cf. http://www.mpdf1.com/forum/discussion/1648/nested-table-bug-
19695 $c['maw'] = $c['w'];
19696 } else {
19697 $c['miw'] = $miw;
19698 } // If cell width not specified -> set Cell min width it to minimum allowed (W)
19699
19700 if (isset($c['miw']) && $c['maw'] < $c['miw']) {
19701 $c['maw'] = $c['miw'];
19702 } // If Cell max width < Minwidth - increase it to =
19703 if (!isset($c['colspan'])) {
19704 if (isset($c['miw']) && $wc['miw'] < $c['miw']) {
19705 $wc['miw'] = $c['miw'];
19706 } // Update Col Minimum and maximum widths
19707 if ($wc['maw'] < $c['maw']) {
19708 $wc['maw'] = $c['maw'];
19709 }
19710 if ((isset($wc['absmiw']) && $wc['absmiw'] < $c['absmiw']) || !isset($wc['absmiw'])) {
19711 $wc['absmiw'] = $c['absmiw'];
19712 } // Update Col Minimum and maximum widths
19713
19714 if (isset($table['l'][$j])) {
19715 $table['l'][$j] += $c['s'];
19716 } else {
19717 $table['l'][$j] = $c['s'];
19718 }
19719 } else {
19720 $listspan[] = [$i, $j];
19721 }
19722
19723 // Check if minimum width of the whole column is big enough for largest word to fit
19724 // mPDF 6
19725 if (isset($c['textbuffer'])) {
19726 if (isset($table['overflow']) && $table['overflow'] == 'wrap') {
19727 $letter = true;
19728 } // check for maximum width of letters
19729 else {
19730 $letter = false;
19731 }
19732 $minwidth = $this->TableCheckMinWidth($wc['miw'] - $extrcw, 0, $c['textbuffer'], $letter);
19733 } else {
19734 $minwidth = 0;
19735 }
19736 if ($minwidth < 0) {
19737 // increase minimum width
19738 if (!isset($c['colspan'])) {
19739 $wc['miw'] = max((isset($wc['miw']) ? $wc['miw'] : 0), ((-$minwidth) + $extrcw));
19740 } else {
19741 $c['miw'] = max((isset($c['miw']) ? $c['miw'] : 0), ((-$minwidth) + $extrcw));
19742 }
19743 }
19744 if (!isset($c['colspan'])) {
19745 if ($wc['miw'] > $wc['maw']) {
19746 $wc['maw'] = $wc['miw'];
19747 } // update maximum width, if needed
19748 }
19749 }
19750 unset($c);
19751 }//rows
19752 }//columns
19753 // COLUMN SPANS
19754 $wc = &$table['wc'];
19755 foreach ($listspan as $span) {
19756 list($i, $j) = $span;
19757 $c = &$cs[$i][$j];
19758 $lc = $j + $c['colspan'];
19759 if ($lc > $nc) {
19760 $lc = $nc;
19761 }
19762 $wis = $wisa = 0;
19763 $was = $wasa = 0;
19764 $list = [];
19765 for ($k = $j; $k < $lc; $k++) {
19766 if (isset($table['l'][$k])) {
19767 if ($c['R']) {
19768 $table['l'][$k] += $c['miw'] / $c['colspan'];
19769 } else {
19770 $table['l'][$k] += $c['s'] / $c['colspan'];
19771 }
19772 } else {
19773 if ($c['R']) {
19774 $table['l'][$k] = $c['miw'] / $c['colspan'];
19775 } else {
19776 $table['l'][$k] = $c['s'] / $c['colspan'];
19777 }
19778 }
19779 $wis += $wc[$k]['miw']; // $wis is the sum of the column miw in the colspan
19780 $was += $wc[$k]['maw']; // $was is the sum of the column maw in the colspan
19781 if (!isset($c['w'])) {
19782 $list[] = $k;
19783 $wisa += $wc[$k]['miw']; // $wisa is the sum of the column miw in cells with no width specified in the colspan
19784 $wasa += $wc[$k]['maw']; // $wasa is the sum of the column maw in cells with no width specified in the colspan
19785 }
19786 }
19787 if ($c['miw'] > $wis) {
19788 if (!$wis) {
19789 for ($k = $j; $k < $lc; $k++) {
19790 $wc[$k]['miw'] = $c['miw'] / $c['colspan'];
19791 }
19792 } elseif (!count($list) && $wis != 0) {
19793 $wi = $c['miw'] - $wis;
19794 for ($k = $j; $k < $lc; $k++) {
19795 $wc[$k]['miw'] += ($wc[$k]['miw'] / $wis) * $wi;
19796 }
19797 } else {
19798 $wi = $c['miw'] - $wis;
19799 // mPDF 5.7.2 Extra min width distributed proportionately to all cells in colspan without a specified width
19800 // cf. http://www.mpdf1.com/forum/discussion/1607#Item_4
19801 foreach ($list as $k) {
19802 if (!isset($wc[$k]['w']) || !$wc[$k]['w']) {
19803 $wc[$k]['miw'] += ($wc[$k]['miw'] / $wisa) * $wi;
19804 }
19805 } // mPDF 5.7.2
19806 }
19807 }
19808 if ($c['maw'] > $was) {
19809 if (!$wis) {
19810 for ($k = $j; $k < $lc; $k++) {
19811 $wc[$k]['maw'] = $c['maw'] / $c['colspan'];
19812 }
19813 } elseif (!count($list) && $was != 0) {
19814 $wi = $c['maw'] - $was;
19815 for ($k = $j; $k < $lc; $k++) {
19816 $wc[$k]['maw'] += ($wc[$k]['maw'] / $was) * $wi;
19817 }
19818 } else {
19819 $wi = $c['maw'] - $was;
19820 // mPDF 5.7.4 Extra max width distributed evenly to all cells in colspan without a specified width
19821 // cf. http://www.mpdf1.com/forum/discussion/2221/colspan-bug
19822 foreach ($list as $k) {
19823 $wc[$k]['maw'] += $wi / count($list);
19824 }
19825 }
19826 }
19827 unset($c);
19828 }
19829
19830 $checkminwidth = 0;
19831 $checkmaxwidth = 0;
19832 $totallength = 0;
19833
19834 for ($i = 0; $i < $nc; $i++) {
19835 $checkminwidth += $table['wc'][$i]['miw'];
19836 $checkmaxwidth += $table['wc'][$i]['maw'];
19837 $totallength += isset($table['l']) ? $table['l'][$i] : 0;
19838 }
19839
19840 if (!isset($table['w']) && $firstpass) {
19841 $sumpc = 0;
19842 $notset = 0;
19843 for ($i = 0; $i < $nc; $i++) {
19844 if (isset($table['wc'][$i]['wpercent']) && $table['wc'][$i]['wpercent']) {
19845 $sumpc += $table['wc'][$i]['wpercent'];
19846 } else {
19847 $notset++;
19848 }
19849 }
19850
19851 // If sum of widths as % >= 100% and not all columns are set
19852 // Set a nominal width of 1% for unset columns
19853 if ($sumpc >= 100 && $notset) {
19854 for ($i = 0; $i < $nc; $i++) {
19855 if ((!isset($table['wc'][$i]['wpercent']) || !$table['wc'][$i]['wpercent']) &&
19856 (!isset($table['wc'][$i]['w']) || !$table['wc'][$i]['w'])) {
19857 $table['wc'][$i]['wpercent'] = 1;
19858 }
19859 }
19860 }
19861
19862
19863 if ($sumpc) { // if any percents are set
19864 $sumnonpc = (100 - $sumpc);
19865 $sumpc = max($sumpc, 100);
19866 $miwleft = 0;
19867 $miwleftcount = 0;
19868 $miwsurplusnonpc = 0;
19869 $maxcalcmiw = 0;
19870 $mawleft = 0;
19871 $mawleftcount = 0;
19872 $mawsurplusnonpc = 0;
19873 $maxcalcmaw = 0;
19874 $mawnon = 0;
19875 $miwnon = 0;
19876 for ($i = 0; $i < $nc; $i++) {
19877 if (isset($table['wc'][$i]['wpercent'])) {
19878 $maxcalcmiw = max($maxcalcmiw, ($table['wc'][$i]['miw'] * $sumpc / $table['wc'][$i]['wpercent']));
19879 $maxcalcmaw = max($maxcalcmaw, ($table['wc'][$i]['maw'] * $sumpc / $table['wc'][$i]['wpercent']));
19880 } else {
19881 $miwleft += $table['wc'][$i]['miw'];
19882 $mawleft += $table['wc'][$i]['maw'];
19883 if (!isset($table['wc'][$i]['w'])) {
19884 $miwleftcount++;
19885 $mawleftcount++;
19886 }
19887 }
19888 }
19889 if ($miwleft && $sumnonpc > 0) {
19890 $miwnon = $miwleft * 100 / $sumnonpc;
19891 }
19892 if ($mawleft && $sumnonpc > 0) {
19893 $mawnon = $mawleft * 100 / $sumnonpc;
19894 }
19895 if (($miwnon > $checkminwidth || $maxcalcmiw > $checkminwidth) && $this->keep_table_proportions) {
19896 if ($miwnon > $maxcalcmiw) {
19897 $miwsurplusnonpc = round((($miwnon * $sumnonpc / 100) - $miwleft), 3);
19898 $checkminwidth = $miwnon;
19899 } else {
19900 $checkminwidth = $maxcalcmiw;
19901 }
19902 for ($i = 0; $i < $nc; $i++) {
19903 if (isset($table['wc'][$i]['wpercent'])) {
19904 $newmiw = $checkminwidth * $table['wc'][$i]['wpercent'] / 100;
19905 if ($table['wc'][$i]['miw'] < $newmiw) {
19906 $table['wc'][$i]['miw'] = $newmiw;
19907 }
19908 $table['wc'][$i]['w'] = 1;
19909 } elseif ($miwsurplusnonpc && !$table['wc'][$i]['w']) {
19910 $table['wc'][$i]['miw'] += $miwsurplusnonpc / $miwleftcount;
19911 }
19912 }
19913 }
19914 if (($mawnon > $checkmaxwidth || $maxcalcmaw > $checkmaxwidth)) {
19915 if ($mawnon > $maxcalcmaw) {
19916 $mawsurplusnonpc = round((($mawnon * $sumnonpc / 100) - $mawleft), 3);
19917 $checkmaxwidth = $mawnon;
19918 } else {
19919 $checkmaxwidth = $maxcalcmaw;
19920 }
19921 for ($i = 0; $i < $nc; $i++) {
19922 if (isset($table['wc'][$i]['wpercent'])) {
19923 $newmaw = $checkmaxwidth * $table['wc'][$i]['wpercent'] / 100;
19924 if ($table['wc'][$i]['maw'] < $newmaw) {
19925 $table['wc'][$i]['maw'] = $newmaw;
19926 }
19927 $table['wc'][$i]['w'] = 1;
19928 } elseif ($mawsurplusnonpc && !$table['wc'][$i]['w']) {
19929 $table['wc'][$i]['maw'] += $mawsurplusnonpc / $mawleftcount;
19930 }
19931 if ($table['wc'][$i]['maw'] < $table['wc'][$i]['miw']) {
19932 $table['wc'][$i]['maw'] = $table['wc'][$i]['miw'];
19933 }
19934 }
19935 }
19936 if ($checkminwidth > $checkmaxwidth) {
19937 $checkmaxwidth = $checkminwidth;
19938 }
19939 }
19940 }
19941
19942 if (isset($table['wpercent']) && $table['wpercent']) {
19943 $checkminwidth *= (100 / $table['wpercent']);
19944 $checkmaxwidth *= (100 / $table['wpercent']);
19945 }
19946
19947
19948 $checkminwidth += $tblbw;
19949 $checkmaxwidth += $tblbw;
19950
19951 // Table['miw'] set by percent in first pass may be larger than sum of column miw
19952 if ((isset($table['miw']) && $checkminwidth > $table['miw']) || !isset($table['miw'])) {
19953 $table['miw'] = $checkminwidth;
19954 }
19955 if ((isset($table['maw']) && $checkmaxwidth > $table['maw']) || !isset($table['maw'])) {
19956 $table['maw'] = $checkmaxwidth;
19957 }
19958 $table['tl'] = $totallength;
19959
19960 // mPDF 6
19961 if ($this->table_rotate) {
19962 $mxw = $this->tbrot_maxw;
19963 } else {
19964 $mxw = $this->blk[$this->blklvl]['inner_width'];
19965 }
19966
19967 if (!isset($table['overflow'])) {
19968 $table['overflow'] = null;
19969 }
19970
19971 if ($table['overflow'] == 'visible') {
19972 return [0, 0];
19973 } elseif ($table['overflow'] == 'hidden' && !$this->table_rotate && !$this->ColActive && $checkminwidth > $mxw) {
19974 $table['w'] = $table['miw'];
19975 return [0, 0];
19976 }
19977 // elseif ($table['overflow']=='wrap') { return array(0,0); } // mPDF 6
19978
19979 if (isset($table['w']) && $table['w']) {
19980
19981 if ($table['w'] >= $checkminwidth && $table['w'] <= $mxw) {
19982 $table['maw'] = $mxw = $table['w'];
19983 } elseif ($table['w'] >= $checkminwidth && $table['w'] > $mxw && $this->keep_table_proportions) {
19984 $checkminwidth = $table['w'];
19985 } elseif ($table['w'] < $checkminwidth && $checkminwidth < $mxw && $this->keep_table_proportions) {
19986 $table['maw'] = $table['w'] = $checkminwidth;
19987 } else {
19988 unset($table['w']);
19989 }
19990 }
19991
19992 $ratio = $checkminwidth / $mxw;
19993
19994 if ($checkminwidth > $mxw) {
19995 return [($ratio + 0.001), $checkminwidth]; // 0.001 to allow for rounded numbers when resizing
19996 }
19997
19998 unset($cs);
19999
20000 return [0, 0];
20001 }
20002
20003 function _tableWidth(&$table)
20004 {
20005 $widthcols = &$table['wc'];
20006 $numcols = $table['nc'];
20007 $tablewidth = 0;
20008
20009 if ($table['borders_separate']) {
20010 $tblbw = $table['border_details']['L']['w'] + $table['border_details']['R']['w'] + $table['margin']['L'] + $table['margin']['R'] + $table['padding']['L'] + $table['padding']['R'] + $table['border_spacing_H'];
20011 } else {
20012 $tblbw = $table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2 + $table['margin']['L'] + $table['margin']['R'];
20013 }
20014
20015 if ($table['level'] > 1 && isset($table['w'])) {
20016
20017 if (isset($table['wpercent']) && $table['wpercent']) {
20018 $table['w'] = $temppgwidth = (($table['w'] - $tblbw) * $table['wpercent'] / 100) + $tblbw;
20019 } else {
20020 $temppgwidth = $table['w'];
20021 }
20022
20023 } elseif ($this->table_rotate) {
20024
20025 $temppgwidth = $this->tbrot_maxw;
20026
20027 // If it is less than 1/20th of the remaining page height to finish the DIV (i.e. DIV padding + table bottom margin) then allow for this
20028 $enddiv = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'];
20029
20030 if ($enddiv / $temppgwidth < 0.05) {
20031 $temppgwidth -= $enddiv;
20032 }
20033
20034 } else {
20035
20036 if (isset($table['w']) && $table['w'] < $this->blk[$this->blklvl]['inner_width']) {
20037 $notfullwidth = 1;
20038 $temppgwidth = $table['w'];
20039 } elseif ($table['overflow'] == 'visible' && $table['level'] == 1) {
20040 $temppgwidth = null;
20041 } elseif ($table['overflow'] == 'hidden' && !$this->ColActive && isset($table['w']) && $table['w'] > $this->blk[$this->blklvl]['inner_width'] && $table['w'] == $table) {
20042 // $temppgwidth = $this->blk[$this->blklvl]['inner_width'];
20043 $temppgwidth = $table['w'];
20044 } else {
20045 $temppgwidth = $this->blk[$this->blklvl]['inner_width'];
20046 }
20047
20048 }
20049
20050 $totaltextlength = 0; // Added - to sum $table['l'][colno]
20051 $totalatextlength = 0; // Added - to sum $table['l'][colno] for those columns where width not set
20052 $percentages_set = 0;
20053
20054 for ($i = 0; $i < $numcols; $i++) {
20055 if (isset($widthcols[$i]['wpercent'])) {
20056 $tablewidth += $widthcols[$i]['maw'];
20057 $percentages_set = 1;
20058 } elseif (isset($widthcols[$i]['w'])) {
20059 $tablewidth += $widthcols[$i]['miw'];
20060 } else {
20061 $tablewidth += $widthcols[$i]['maw'];
20062 }
20063 $totaltextlength += isset($table['l']) ? $table['l'][$i] : 0;
20064 }
20065
20066 if (!$totaltextlength) {
20067 $totaltextlength = 1;
20068 }
20069
20070 $tablewidth += $tblbw; // Outer half of table borders
20071
20072 if ($tablewidth > $temppgwidth) {
20073 $table['w'] = $temppgwidth;
20074 } elseif ($tablewidth < $temppgwidth && !isset($table['w']) && $percentages_set) { // if any widths set as percentages and max width fits < page width
20075 $table['w'] = $table['maw'];
20076 }
20077
20078 // if table width is set and is > allowed width
20079 if (isset($table['w']) && $table['w'] > $temppgwidth) {
20080 $table['w'] = $temppgwidth;
20081 }
20082
20083 // IF the table width is now set - Need to distribute columns widths
20084 // mPDF 5.7.3
20085 // If the table width is already set to the maximum width (e.g. nested table), then use maximum column widths exactly
20086 if (isset($table['w']) && ($table['w'] == $tablewidth) && !$percentages_set) {
20087
20088 // This sets the columns all to maximum width
20089 for ($i = 0; $i < $numcols; $i++) {
20090 $widthcols[$i] = $widthcols[$i]['maw'];
20091 }
20092
20093 } elseif (isset($table['w'])) { // elseif the table width is set distribute width using algorithm
20094
20095 $wis = $wisa = 0;
20096 $list = [];
20097 $notsetlist = [];
20098
20099 for ($i = 0; $i < $numcols; $i++) {
20100 $wis += $widthcols[$i]['miw'];
20101 if (!isset($widthcols[$i]['w']) || ($widthcols[$i]['w'] && $table['w'] > $temppgwidth && !$this->keep_table_proportions && !$notfullwidth )) {
20102 $list[] = $i;
20103 $wisa += $widthcols[$i]['miw'];
20104 $totalatextlength += $table['l'][$i];
20105 }
20106 }
20107
20108 if (!$totalatextlength) {
20109 $totalatextlength = 1;
20110 }
20111
20112 // Allocate spare (more than col's minimum width) across the cols according to their approx total text length
20113 // Do it by setting minimum width here
20114 if ($table['w'] > $wis + $tblbw) {
20115
20116 // First set any cell widths set as percentages
20117 if ($table['w'] < $temppgwidth || $this->keep_table_proportions) {
20118 for ($k = 0; $k < $numcols; $k++) {
20119 if (isset($widthcols[$k]['wpercent'])) {
20120 $curr = $widthcols[$k]['miw'];
20121 $widthcols[$k]['miw'] = ($table['w'] - $tblbw) * $widthcols[$k]['wpercent'] / 100;
20122 $wis += $widthcols[$k]['miw'] - $curr;
20123 $wisa += $widthcols[$k]['miw'] - $curr;
20124 }
20125 }
20126 }
20127
20128 // Now allocate surplus up to maximum width of each column
20129 $surplus = 0;
20130 $ttl = 0; // number of surplus columns
20131
20132 if (!count($list)) {
20133
20134 $wi = ($table['w'] - ($wis + $tblbw)); // i.e. extra space to distribute
20135
20136 for ($k = 0; $k < $numcols; $k++) {
20137
20138 $spareratio = ($table['l'][$k] / $totaltextlength); // gives ratio to divide up free space
20139
20140 // Don't allocate more than Maximum required width - save rest in surplus
20141 if ($widthcols[$k]['miw'] + ($wi * $spareratio) >= $widthcols[$k]['maw']) { // mPDF 5.7.3
20142 $surplus += ($wi * $spareratio) - ($widthcols[$k]['maw'] - $widthcols[$k]['miw']);
20143 $widthcols[$k]['miw'] = $widthcols[$k]['maw'];
20144 } else {
20145 $notsetlist[] = $k;
20146 $ttl += $table['l'][$k];
20147 $widthcols[$k]['miw'] += ($wi * $spareratio);
20148 }
20149 }
20150
20151 } else {
20152
20153 $wi = ($table['w'] - ($wis + $tblbw)); // i.e. extra space to distribute
20154
20155 foreach ($list as $k) {
20156
20157 $spareratio = ($table['l'][$k] / $totalatextlength); // gives ratio to divide up free space
20158
20159 // Don't allocate more than Maximum required width - save rest in surplus
20160 if ($widthcols[$k]['miw'] + ($wi * $spareratio) >= $widthcols[$k]['maw']) { // mPDF 5.7.3
20161 $surplus += ($wi * $spareratio) - ($widthcols[$k]['maw'] - $widthcols[$k]['miw']);
20162 $widthcols[$k]['miw'] = $widthcols[$k]['maw'];
20163 } else {
20164 $notsetlist[] = $k;
20165 $ttl += $table['l'][$k];
20166 $widthcols[$k]['miw'] += ($wi * $spareratio);
20167 }
20168 }
20169 }
20170
20171 // If surplus still left over apportion it across columns
20172 if ($surplus) {
20173
20174 if (count($notsetlist) && count($notsetlist) < $numcols) { // if some are set only add to remaining - otherwise add to all of them
20175 foreach ($notsetlist as $i) {
20176 if ($ttl) {
20177 $widthcols[$i]['miw'] += $surplus * $table['l'][$i] / $ttl;
20178 }
20179 }
20180 } elseif (count($list) && count($list) < $numcols) { // If some widths are defined, and others have been added up to their maxmum
20181 foreach ($list as $i) {
20182 $widthcols[$i]['miw'] += $surplus / count($list);
20183 }
20184 } elseif ($numcols) { // If all columns
20185 $ttl = array_sum($table['l']);
20186 if ($ttl) {
20187 for ($i = 0; $i < $numcols; $i++) {
20188 $widthcols[$i]['miw'] += $surplus * $table['l'][$i] / $ttl;
20189 }
20190 }
20191 }
20192 }
20193 }
20194
20195 // This sets the columns all to minimum width (which has been increased above if appropriate)
20196 for ($i = 0; $i < $numcols; $i++) {
20197 $widthcols[$i] = $widthcols[$i]['miw'];
20198 }
20199
20200 // TABLE NOT WIDE ENOUGH EVEN FOR MINIMUM CONTENT WIDTH
20201 // If sum of column widths set are too wide for table
20202 $checktablewidth = 0;
20203 for ($i = 0; $i < $numcols; $i++) {
20204 $checktablewidth += $widthcols[$i];
20205 }
20206
20207 if ($checktablewidth > ($temppgwidth + 0.001 - $tblbw)) {
20208
20209 $usedup = 0;
20210 $numleft = 0;
20211
20212 for ($i = 0; $i < $numcols; $i++) {
20213 if ((isset($widthcols[$i]) && $widthcols[$i] > (($temppgwidth - $tblbw) / $numcols)) && (!isset($widthcols[$i]['w']))) {
20214 $numleft++;
20215 unset($widthcols[$i]);
20216 } else {
20217 $usedup += $widthcols[$i];
20218 }
20219 }
20220
20221 for ($i = 0; $i < $numcols; $i++) {
20222 if (!isset($widthcols[$i]) || !$widthcols[$i]) {
20223 $widthcols[$i] = ((($temppgwidth - $tblbw) - $usedup) / ($numleft));
20224 }
20225 }
20226 }
20227
20228 } else { // table has no width defined
20229
20230 $table['w'] = $tablewidth;
20231
20232 for ($i = 0; $i < $numcols; $i++) {
20233
20234 if (isset($widthcols[$i]['wpercent']) && $this->keep_table_proportions) {
20235 $colwidth = $widthcols[$i]['maw'];
20236 } elseif (isset($widthcols[$i]['w'])) {
20237 $colwidth = $widthcols[$i]['miw'];
20238 } else {
20239 $colwidth = $widthcols[$i]['maw'];
20240 }
20241
20242 unset($widthcols[$i]);
20243 $widthcols[$i] = $colwidth;
20244
20245 }
20246 }
20247
20248 if ($table['overflow'] === 'visible' && $table['level'] == 1) {
20249
20250 if ($tablewidth > $this->blk[$this->blklvl]['inner_width']) {
20251
20252 for ($j = 0; $j < $numcols; $j++) { // columns
20253
20254 for ($i = 0; $i < $table['nr']; $i++) { // rows
20255
20256 if (isset($table['cells'][$i][$j]) && $table['cells'][$i][$j]) {
20257
20258 $colspan = (isset($table['cells'][$i][$j]['colspan']) ? $table['cells'][$i][$j]['colspan'] : 1);
20259
20260 if ($colspan > 1) {
20261 $w = 0;
20262
20263 for ($c = $j; $c < ($j + $colspan); $c++) {
20264 $w += $widthcols[$c];
20265 }
20266
20267 if ($w > $this->blk[$this->blklvl]['inner_width']) {
20268 $diff = $w - ($this->blk[$this->blklvl]['inner_width'] - $tblbw);
20269 for ($c = $j; $c < ($j + $colspan); $c++) {
20270 $widthcols[$c] -= $diff * ($widthcols[$c] / $w);
20271 }
20272 $table['w'] -= $diff;
20273 $table['csp'][$j] = $w - $diff;
20274 }
20275 }
20276 }
20277 }
20278 }
20279 }
20280
20281 $pgNo = 0;
20282 $currWc = 0;
20283
20284 for ($i = 0; $i < $numcols; $i++) { // columns
20285
20286 if (isset($table['csp'][$i])) {
20287 $w = $table['csp'][$i];
20288 unset($table['csp'][$i]);
20289 } else {
20290 $w = $widthcols[$i];
20291 }
20292
20293 if (($currWc + $w + $tblbw) > $this->blk[$this->blklvl]['inner_width']) {
20294 $pgNo++;
20295 $currWc = $widthcols[$i];
20296 } else {
20297 $currWc += $widthcols[$i];
20298 }
20299
20300 $table['colPg'][$i] = $pgNo;
20301 }
20302 }
20303 }
20304
20305 function _tableHeight(&$table)
20306 {
20307 $level = $table['level'];
20308 $levelid = $table['levelid'];
20309 $cells = &$table['cells'];
20310 $numcols = $table['nc'];
20311 $numrows = $table['nr'];
20312 $listspan = [];
20313 $checkmaxheight = 0;
20314 $headerrowheight = 0;
20315 $checkmaxheightplus = 0;
20316 $headerrowheightplus = 0;
20317 $firstrowheight = 0;
20318
20319 $footerrowheight = 0;
20320 $footerrowheightplus = 0;
20321 if ($this->table_rotate) {
20322 $temppgheight = $this->tbrot_maxh;
20323 $remainingpage = $this->tbrot_maxh;
20324 } else {
20325 $temppgheight = ($this->h - $this->bMargin - $this->tMargin) - $this->kwt_height;
20326 $remainingpage = ($this->h - $this->bMargin - $this->y) - $this->kwt_height;
20327
20328 // If it is less than 1/20th of the remaining page height to finish the DIV (i.e. DIV padding + table bottom margin)
20329 // then allow for this
20330 $enddiv = $this->blk[$this->blklvl]['padding_bottom'] + $this->blk[$this->blklvl]['border_bottom']['w'] + $table['margin']['B'];
20331 if ($remainingpage > $enddiv && $enddiv / $remainingpage < 0.05) {
20332 $remainingpage -= $enddiv;
20333 } elseif ($remainingpage == 0) {
20334 $remainingpage = 0.001;
20335 }
20336 if ($temppgheight > $enddiv && $enddiv / $temppgheight < 0.05) {
20337 $temppgheight -= $enddiv;
20338 } elseif ($temppgheight == 0) {
20339 $temppgheight = 0.001;
20340 }
20341 }
20342 if ($remainingpage < 0) {
20343 $remainingpage = 0.001;
20344 }
20345 if ($temppgheight < 0) {
20346 $temppgheight = 0.001;
20347 }
20348
20349 for ($i = 0; $i < $numrows; $i++) { // rows
20350 $heightrow = &$table['hr'][$i];
20351 for ($j = 0; $j < $numcols; $j++) { // columns
20352 if (isset($cells[$i][$j]) && $cells[$i][$j]) {
20353 $c = &$cells[$i][$j];
20354
20355 if ($this->simpleTables) {
20356 if ($table['borders_separate']) { // NB twice border width
20357 $extraWLR = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) + ($c['padding']['L'] + $c['padding']['R']) + $table['border_spacing_H'];
20358 $extrh = ($table['simple']['border_details']['T']['w'] + $table['simple']['border_details']['B']['w']) + ($c['padding']['T'] + $c['padding']['B']) + $table['border_spacing_V'];
20359 } else {
20360 $extraWLR = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) / 2 + ($c['padding']['L'] + $c['padding']['R']);
20361 $extrh = ($table['simple']['border_details']['T']['w'] + $table['simple']['border_details']['B']['w']) / 2 + ($c['padding']['T'] + $c['padding']['B']);
20362 }
20363 } else {
20364 if ($this->packTableData) {
20365 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
20366 } else {
20367 $bt = $c['border_details']['T']['w'];
20368 $bb = $c['border_details']['B']['w'];
20369 $br = $c['border_details']['R']['w'];
20370 $bl = $c['border_details']['L']['w'];
20371 }
20372 if ($table['borders_separate']) { // NB twice border width
20373 $extraWLR = $bl + $br + $c['padding']['L'] + $c['padding']['R'] + $table['border_spacing_H'];
20374 $extrh = $bt + $bb + $c['padding']['T'] + $c['padding']['B'] + $table['border_spacing_V'];
20375 } else {
20376 $extraWLR = $bl / 2 + $br / 2 + $c['padding']['L'] + $c['padding']['R'];
20377 $extrh = $bt / 2 + $bb / 2 + $c['padding']['T'] + $c['padding']['B'];
20378 }
20379 }
20380
20381 if ($table['overflow'] == 'visible' && $level == 1) {
20382 list($x, $cw) = $this->_splitTableGetWidth($table, $i, $j);
20383 } else {
20384 list($x, $cw) = $this->_tableGetWidth($table, $i, $j);
20385 }
20386
20387
20388 // Get CELL HEIGHT
20389 // ++ extra parameter forces wrap to break word
20390 if ($c['R'] && isset($c['textbuffer'])) {
20391 $str = '';
20392 foreach ($c['textbuffer'] as $t) {
20393 $str .= $t[0] . ' ';
20394 }
20395 $str = rtrim($str);
20396 $s_fs = $this->FontSizePt;
20397 $s_f = $this->FontFamily;
20398 $s_st = $this->FontStyle;
20399 $this->SetFont($c['textbuffer'][0][4], $c['textbuffer'][0][2], $c['textbuffer'][0][11] / $this->shrin_k, true, true);
20400 $tempch = $this->GetStringWidth($str, true, $c['textbuffer'][0][18], $c['textbuffer'][0][8]);
20401 if ($c['R'] >= 45 && $c['R'] < 90) {
20402 $tempch = ((sin(deg2rad($c['R']))) * $tempch ) + ((sin(deg2rad($c['R']))) * (($c['textbuffer'][0][11] / Mpdf::SCALE) / $this->shrin_k));
20403 }
20404 $this->SetFont($s_f, $s_st, $s_fs, true, true);
20405 $ch = ($tempch ) + $extrh;
20406 } else {
20407 if (isset($c['textbuffer']) && !empty($c['textbuffer'])) {
20408 $this->cellLineHeight = $c['cellLineHeight'];
20409 $this->cellLineStackingStrategy = $c['cellLineStackingStrategy'];
20410 $this->cellLineStackingShift = $c['cellLineStackingShift'];
20411 $this->divwidth = $cw - $extraWLR;
20412 $tempch = $this->printbuffer($c['textbuffer'], '', true, true);
20413 } else {
20414 $tempch = 0;
20415 }
20416
20417 // Added cellpadding top and bottom. (Lineheight already adjusted)
20418 $ch = $tempch + $extrh;
20419 }
20420 // If height is defined and it is bigger than calculated $ch then update values
20421 if (isset($c['h']) && $c['h'] > $ch) {
20422 $c['mih'] = $ch; // in order to keep valign working
20423 $ch = $c['h'];
20424 } else {
20425 $c['mih'] = $ch;
20426 }
20427 if (isset($c['rowspan'])) {
20428 $listspan[] = [$i, $j];
20429 } elseif ($heightrow < $ch) {
20430 $heightrow = $ch;
20431 }
20432
20433 // this is the extra used in _tableWrite to determine whether to trigger a page change
20434 if ($table['borders_separate']) {
20435 if ($i == ($numrows - 1) || (isset($c['rowspan']) && ($i + $c['rowspan']) == ($numrows))) {
20436 $extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
20437 } else {
20438 $extra = $table['border_spacing_V'] / 2;
20439 }
20440 } else {
20441 if (!$this->simpleTables) {
20442 $extra = $bb / 2;
20443 } elseif ($this->simpleTables) {
20444 $extra = $table['simple']['border_details']['B']['w'] / 2;
20445 }
20446 }
20447 if (isset($table['is_thead'][$i]) && $table['is_thead'][$i]) {
20448 if ($j == 0) {
20449 $headerrowheight += $ch;
20450 $headerrowheightplus += $ch + $extra;
20451 }
20452 } elseif (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i]) {
20453 if ($j == 0) {
20454 $footerrowheight += $ch;
20455 $footerrowheightplus += $ch + $extra;
20456 }
20457 } else {
20458 $checkmaxheight = max($checkmaxheight, $ch);
20459 $checkmaxheightplus = max($checkmaxheightplus, $ch + $extra);
20460 }
20461 if ($this->tableLevel == 1 && $i == (isset($table['headernrows']) ? $table['headernrows'] : 0)) {
20462 $firstrowheight = max($ch, $firstrowheight);
20463 }
20464 unset($c);
20465 }
20466 }//end of columns
20467 }//end of rows
20468
20469 $heightrow = &$table['hr'];
20470 foreach ($listspan as $span) {
20471 list($i, $j) = $span;
20472 $c = &$cells[$i][$j];
20473 $lr = $i + $c['rowspan'];
20474 if ($lr > $numrows) {
20475 $lr = $numrows;
20476 }
20477 $hs = $hsa = 0;
20478 $list = [];
20479 for ($k = $i; $k < $lr; $k++) {
20480 $hs += $heightrow[$k];
20481 // mPDF 6
20482 $sh = false; // specified height
20483 for ($m = 0; $m < $numcols; $m++) { // columns
20484 $tc = &$cells[$k][$m];
20485 if (isset($tc['rowspan'])) {
20486 continue;
20487 }
20488 if (isset($tc['h'])) {
20489 $sh = true;
20490 break;
20491 }
20492 }
20493 if (!$sh) {
20494 $list[] = $k;
20495 }
20496 }
20497
20498 if ($table['borders_separate']) {
20499 if ($i == ($numrows - 1) || ($i + $c['rowspan']) == ($numrows)) {
20500 $extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
20501 } else {
20502 $extra = $table['border_spacing_V'] / 2;
20503 }
20504 } else {
20505 if (!$this->simpleTables) {
20506 if ($this->packTableData) {
20507 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($c['borderbin']);
20508 } else {
20509 $bb = $c['border_details']['B']['w'];
20510 }
20511 $extra = $bb / 2;
20512 } elseif ($this->simpleTables) {
20513 $extra = $table['simple']['border_details']['B']['w'] / 2;
20514 }
20515 }
20516 if (!empty($table['is_thead'][$i])) {
20517 $headerrowheight = max($headerrowheight, $hs);
20518 $headerrowheightplus = max($headerrowheightplus, $hs + $extra);
20519 } elseif (!empty($table['is_tfoot'][$i])) {
20520 $footerrowheight = max($footerrowheight, $hs);
20521 $footerrowheightplus = max($footerrowheightplus, $hs + $extra);
20522 } else {
20523 $checkmaxheight = max($checkmaxheight, $hs);
20524 $checkmaxheightplus = max($checkmaxheightplus, $hs + $extra);
20525 }
20526 if ($this->tableLevel == 1 && $i == (isset($table['headernrows']) ? $table['headernrows'] : 0)) {
20527 $firstrowheight = max($hs, $firstrowheight);
20528 }
20529
20530 if ($c['mih'] > $hs) {
20531 if (!$hs) {
20532 for ($k = $i; $k < $lr; $k++) {
20533 $heightrow[$k] = $c['mih'] / $c['rowspan'];
20534 }
20535 } elseif (!count($list)) { // no rows in the rowspan have a height specified, so share amongst all rows equally
20536 $hi = $c['mih'] - $hs;
20537 for ($k = $i; $k < $lr; $k++) {
20538 $heightrow[$k] += ($heightrow[$k] / $hs) * $hi;
20539 }
20540 } else {
20541 $hi = $c['mih'] - $hs; // mPDF 6
20542 foreach ($list as $k) {
20543 $heightrow[$k] += $hi / (count($list)); // mPDF 6
20544 }
20545 }
20546 }
20547 unset($c);
20548
20549 // If rowspans overlap so that one or more rows do not have a height set...
20550 // i.e. for one or more rows, the only cells (explicit) in that row have rowspan>1
20551 // so heightrow is still == 0
20552 if ($heightrow[$i] == 0) {
20553 // Get row extent to analyse above and below
20554 $top = $i;
20555 foreach ($listspan as $checkspan) {
20556 list($cki, $ckj) = $checkspan;
20557 $c = &$cells[$cki][$ckj];
20558 if (isset($c['rowspan']) && $c['rowspan'] > 1) {
20559 if (($cki + $c['rowspan'] - 1) >= $i) {
20560 $top = min($top, $cki);
20561 }
20562 }
20563 }
20564 $bottom = $i + $c['rowspan'] - 1;
20565 // Check for overconstrained conditions
20566 for ($k = $top; $k <= $bottom; $k++) {
20567 // if ['hr'] for any of the others is also 0, then abort (too complicated)
20568 if ($k != $i && $heightrow[$k] == 0) {
20569 break(1);
20570 }
20571 // check again that top and bottom are not crossed by rowspans - or abort (too complicated)
20572 if ($k == $top) {
20573 // ???? take account of colspan as well???
20574 for ($m = 0; $m < $numcols; $m++) { // columns
20575 if (!isset($cells[$k][$m]) || $cells[$k][$m] == 0) {
20576 break(2);
20577 }
20578 }
20579 } elseif ($k == $bottom) {
20580 // ???? take account of colspan as well???
20581 for ($m = 0; $m < $numcols; $m++) { // columns
20582 $c = &$cells[$k][$m];
20583 if (isset($c['rowspan']) && $c['rowspan'] > 1) {
20584 break(2);
20585 }
20586 }
20587 }
20588 }
20589 // By columns add up col height using ['h'] if set or ['mih'] if not
20590 // Intentionally do not substract border-spacing
20591 $colH = [];
20592 $extH = 0;
20593 $newhr = [];
20594 for ($m = 0; $m < $numcols; $m++) { // columns
20595 for ($k = $top; $k <= $bottom; $k++) {
20596 if (isset($cells[$k][$m]) && $cells[$k][$m] != 0) {
20597 $c = &$cells[$k][$m];
20598 if (isset($c['h']) && $c['h']) {
20599 $useh = $c['h'];
20600 } // ???? take account of colspan as well???
20601 else {
20602 $useh = $c['mih'];
20603 }
20604 if (isset($colH[$m])) {
20605 $colH[$m] += $useh;
20606 } else {
20607 $colH[$m] = $useh;
20608 }
20609 if (!isset($c['rowspan']) || $c['rowspan'] < 2) {
20610 $newhr[$k] = max((isset($newhr[$k]) ? $newhr[$k] : 0), $useh);
20611 }
20612 }
20613 }
20614 $extH = max($extH, $colH[$m]); // mPDF 6
20615 }
20616 $newhr[$i] = $extH - array_sum($newhr);
20617 for ($k = $top; $k <= $bottom; $k++) {
20618 $heightrow[$k] = $newhr[$k];
20619 }
20620 }
20621
20622
20623 unset($c);
20624 }
20625
20626 $table['h'] = array_sum($heightrow);
20627 unset($heightrow);
20628
20629 if ($table['borders_separate']) {
20630 $table['h'] += $table['margin']['T'] + $table['margin']['B'] + $table['border_details']['T']['w'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] + $table['padding']['T'] + $table['padding']['B'];
20631 } else {
20632 $table['h'] += $table['margin']['T'] + $table['margin']['B'] + $table['max_cell_border_width']['T'] / 2 + $table['max_cell_border_width']['B'] / 2;
20633 }
20634
20635 $maxrowheight = $checkmaxheightplus + $headerrowheightplus + $footerrowheightplus;
20636 $maxfirstrowheight = $firstrowheight + $headerrowheightplus + $footerrowheightplus; // includes thead, 1st row and tfoot
20637 return [$table['h'], $maxrowheight, $temppgheight, $remainingpage, $maxfirstrowheight];
20638 }
20639
20640 function _tableGetWidth(&$table, $i, $j)
20641 {
20642 $cell = &$table['cells'][$i][$j];
20643 if ($cell) {
20644 if (isset($cell['x0'])) {
20645 return [$cell['x0'], $cell['w0']];
20646 }
20647 $x = 0;
20648 $widthcols = &$table['wc'];
20649 for ($k = 0; $k < $j; $k++) {
20650 $x += $widthcols[$k];
20651 }
20652 $w = $widthcols[$j];
20653 if (isset($cell['colspan'])) {
20654 for ($k = $j + $cell['colspan'] - 1; $k > $j; $k--) {
20655 $w += $widthcols[$k];
20656 }
20657 }
20658 $cell['x0'] = $x;
20659 $cell['w0'] = $w;
20660 return [$x, $w];
20661 }
20662 return [0, 0];
20663 }
20664
20665 function _splitTableGetWidth(&$table, $i, $j)
20666 {
20667 $cell = &$table['cells'][$i][$j];
20668 if ($cell) {
20669 if (isset($cell['x0'])) {
20670 return [$cell['x0'], $cell['w0']];
20671 }
20672 $x = 0;
20673 $widthcols = &$table['wc'];
20674 $pg = $table['colPg'][$j];
20675 for ($k = 0; $k < $j; $k++) {
20676 if ($table['colPg'][$k] == $pg) {
20677 $x += $widthcols[$k];
20678 }
20679 }
20680 $w = $widthcols[$j];
20681 if (isset($cell['colspan'])) {
20682 for ($k = $j + $cell['colspan'] - 1; $k > $j; $k--) {
20683 if ($table['colPg'][$k] == $pg) {
20684 $w += $widthcols[$k];
20685 }
20686 }
20687 }
20688 $cell['x0'] = $x;
20689 $cell['w0'] = $w;
20690 return [$x, $w];
20691 }
20692 return [0, 0];
20693 }
20694
20695 function _tableGetHeight(&$table, $i, $j)
20696 {
20697 $cell = &$table['cells'][$i][$j];
20698 if ($cell) {
20699 if (isset($cell['y0'])) {
20700 return [$cell['y0'], $cell['h0']];
20701 }
20702 $y = 0;
20703 $heightrow = &$table['hr'];
20704 for ($k = 0; $k < $i; $k++) {
20705 $y += $heightrow[$k];
20706 }
20707 $h = $heightrow[$i];
20708 if (isset($cell['rowspan'])) {
20709 for ($k = $i + $cell['rowspan'] - 1; $k > $i; $k--) {
20710 if (array_key_exists($k, $heightrow)) {
20711 $h += $heightrow[$k];
20712 } else {
20713 $this->logger->debug('Possible non-wellformed HTML markup in a table', ['context' => LogContext::HTML_MARKUP]);
20714 }
20715 }
20716 }
20717 $cell['y0'] = $y;
20718 $cell['h0'] = $h;
20719 return [$y, $h];
20720 }
20721 return [0, 0];
20722 }
20723
20724 function _tableGetMaxRowHeight($table, $row)
20725 {
20726 if ($row == $table['nc'] - 1) {
20727 return $table['hr'][$row];
20728 }
20729 $maxrowheight = $table['hr'][$row];
20730 for ($i = $row + 1; $i < $table['nr']; $i++) {
20731 $cellsset = 0;
20732 for ($j = 0; $j < $table['nc']; $j++) {
20733 if ($table['cells'][$i][$j]) {
20734 if (isset($table['cells'][$i][$j]['colspan'])) {
20735 $cellsset += $table['cells'][$i][$j]['colspan'];
20736 } else {
20737 $cellsset += 1;
20738 }
20739 }
20740 }
20741 if ($cellsset == $table['nc']) {
20742 return $maxrowheight;
20743 } else {
20744 $maxrowheight += $table['hr'][$i];
20745 }
20746 }
20747 return $maxrowheight;
20748 }
20749
20750 // CHANGED TO ALLOW TABLE BORDER TO BE SPECIFIED CORRECTLY - added border_details
20751 function _tableRect($x, $y, $w, $h, $bord = -1, $details = [], $buffer = false, $bSeparate = false, $cort = 'cell', $tablecorner = '', $bsv = 0, $bsh = 0)
20752 {
20753 $cellBorderOverlay = [];
20754
20755 if ($bord == -1) {
20756 $this->Rect($x, $y, $w, $h);
20757 } elseif ($this->simpleTables && ($cort == 'cell')) {
20758 $this->SetLineWidth($details['L']['w']);
20759 if ($details['L']['c']) {
20760 $this->SetDColor($details['L']['c']);
20761 } else {
20762 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
20763 }
20764 $this->SetLineJoin(0);
20765 $this->Rect($x, $y, $w, $h);
20766 } elseif ($bord) {
20767 if (!$bSeparate && $buffer) {
20768 $priority = 'LRTB';
20769 for ($p = 0; $p < strlen($priority); $p++) {
20770 $side = $priority[$p];
20771 $details['p'] = $side;
20772
20773 $dom = 0;
20774 if (isset($details[$side]['w'])) {
20775 $dom += ($details[$side]['w'] * 100000);
20776 }
20777 if (isset($details[$side]['style'])) {
20778 $dom += (array_search($details[$side]['style'], $this->borderstyles) * 100);
20779 }
20780 if (isset($details[$side]['dom'])) {
20781 $dom += ($details[$side]['dom'] * 10);
20782 }
20783
20784 // Precedence to darker colours at joins
20785 $coldom = 0;
20786 if (isset($details[$side]['c']) && is_array($details[$side]['c'])) {
20787 if ($details[$side]['c'][0] == 3) { // RGB
20788 $coldom = 10 - (((ord($details[$side]['c'][1]) * 1.00) + (ord($details[$side]['c'][2]) * 1.00) + (ord($details[$side]['c'][3]) * 1.00)) / 76.5);
20789 }
20790 } // 10 black - 0 white
20791 if ($coldom) {
20792 $dom += $coldom;
20793 }
20794 // Lastly precedence to RIGHT and BOTTOM cells at joins
20795 if (isset($details['cellposdom'])) {
20796 $dom += $details['cellposdom'];
20797 }
20798
20799 $save = false;
20800 if ($side == 'T' && $this->issetBorder($bord, Border::TOP)) {
20801 $cbord = Border::TOP;
20802 $save = true;
20803 } elseif ($side == 'L' && $this->issetBorder($bord, Border::LEFT)) {
20804 $cbord = Border::LEFT;
20805 $save = true;
20806 } elseif ($side == 'R' && $this->issetBorder($bord, Border::RIGHT)) {
20807 $cbord = Border::RIGHT;
20808 $save = true;
20809 } elseif ($side == 'B' && $this->issetBorder($bord, Border::BOTTOM)) {
20810 $cbord = Border::BOTTOM;
20811 $save = true;
20812 }
20813
20814 if ($save) {
20815 $this->cellBorderBuffer[] = pack("A16nCnda6A10d14", str_pad(sprintf("%08.7f", $dom), 16, "0", STR_PAD_LEFT), $cbord, ord($side), $details[$side]['s'], $details[$side]['w'], $details[$side]['c'], $details[$side]['style'], $x, $y, $w, $h, $details['mbw']['BL'], $details['mbw']['BR'], $details['mbw']['RT'], $details['mbw']['RB'], $details['mbw']['TL'], $details['mbw']['TR'], $details['mbw']['LT'], $details['mbw']['LB'], $details['cellposdom'], 0);
20816 if ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'groove' || $details[$side]['style'] == 'inset' || $details[$side]['style'] == 'outset' || $details[$side]['style'] == 'double') {
20817 $details[$side]['overlay'] = true;
20818 $this->cellBorderBuffer[] = pack("A16nCnda6A10d14", str_pad(sprintf("%08.7f", ($dom + 4)), 16, "0", STR_PAD_LEFT), $cbord, ord($side), $details[$side]['s'], $details[$side]['w'], $details[$side]['c'], $details[$side]['style'], $x, $y, $w, $h, $details['mbw']['BL'], $details['mbw']['BR'], $details['mbw']['RT'], $details['mbw']['RB'], $details['mbw']['TL'], $details['mbw']['TR'], $details['mbw']['LT'], $details['mbw']['LB'], $details['cellposdom'], 1);
20819 }
20820 }
20821 }
20822 return;
20823 }
20824
20825 if (isset($details['p']) && strlen($details['p']) > 1) {
20826 $priority = $details['p'];
20827 } else {
20828 $priority = 'LTRB';
20829 }
20830 $Tw = 0;
20831 $Rw = 0;
20832 $Bw = 0;
20833 $Lw = 0;
20834 if (isset($details['T']['w'])) {
20835 $Tw = $details['T']['w'];
20836 }
20837 if (isset($details['R']['w'])) {
20838 $Rw = $details['R']['w'];
20839 }
20840 if (isset($details['B']['w'])) {
20841 $Bw = $details['B']['w'];
20842 }
20843 if (isset($details['L']['w'])) {
20844 $Lw = $details['L']['w'];
20845 }
20846
20847 $x2 = $x + $w;
20848 $y2 = $y + $h;
20849 $oldlinewidth = $this->LineWidth;
20850
20851 for ($p = 0; $p < strlen($priority); $p++) {
20852 $side = $priority[$p];
20853 $xadj = 0;
20854 $xadj2 = 0;
20855 $yadj = 0;
20856 $yadj2 = 0;
20857 $print = false;
20858 if ($Tw && $side == 'T' && $this->issetBorder($bord, Border::TOP)) { // TOP
20859 $ly1 = $y;
20860 $ly2 = $y;
20861 $lx1 = $x;
20862 $lx2 = $x2;
20863 $this->SetLineWidth($Tw);
20864 if ($cort == 'cell' || strpos($tablecorner, 'L') !== false) {
20865 if ($Tw > $Lw) {
20866 $xadj = ($Tw - $Lw) / 2;
20867 }
20868 if ($Tw < $Lw) {
20869 $xadj = ($Tw + $Lw) / 2;
20870 }
20871 } else {
20872 $xadj = $Tw / 2 - $bsh / 2;
20873 }
20874 if ($cort == 'cell' || strpos($tablecorner, 'R') !== false) {
20875 if ($Tw > $Rw) {
20876 $xadj2 = ($Tw - $Rw) / 2;
20877 }
20878 if ($Tw < $Rw) {
20879 $xadj2 = ($Tw + $Rw) / 2;
20880 }
20881 } else {
20882 $xadj2 = $Tw / 2 - $bsh / 2;
20883 }
20884 if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['TL'])) {
20885 $xadj = ($Tw - $details['mbw']['TL']) / 2;
20886 }
20887 if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['TR'])) {
20888 $xadj2 = ($Tw - $details['mbw']['TR']) / 2;
20889 }
20890 $print = true;
20891 }
20892 if ($Lw && $side == 'L' && $this->issetBorder($bord, Border::LEFT)) { // LEFT
20893 $ly1 = $y;
20894 $ly2 = $y2;
20895 $lx1 = $x;
20896 $lx2 = $x;
20897 $this->SetLineWidth($Lw);
20898 if ($cort == 'cell' || strpos($tablecorner, 'T') !== false) {
20899 if ($Lw > $Tw) {
20900 $yadj = ($Lw - $Tw) / 2;
20901 }
20902 if ($Lw < $Tw) {
20903 $yadj = ($Lw + $Tw) / 2;
20904 }
20905 } else {
20906 $yadj = $Lw / 2 - $bsv / 2;
20907 }
20908 if ($cort == 'cell' || strpos($tablecorner, 'B') !== false) {
20909 if ($Lw > $Bw) {
20910 $yadj2 = ($Lw - $Bw) / 2;
20911 }
20912 if ($Lw < $Bw) {
20913 $yadj2 = ($Lw + $Bw) / 2;
20914 }
20915 } else {
20916 $yadj2 = $Lw / 2 - $bsv / 2;
20917 }
20918 if (!$bSeparate && $details['mbw']['LT']) {
20919 $yadj = ($Lw - $details['mbw']['LT']) / 2;
20920 }
20921 if (!$bSeparate && $details['mbw']['LB']) {
20922 $yadj2 = ($Lw - $details['mbw']['LB']) / 2;
20923 }
20924 $print = true;
20925 }
20926 if ($Rw && $side == 'R' && $this->issetBorder($bord, Border::RIGHT)) { // RIGHT
20927 $ly1 = $y;
20928 $ly2 = $y2;
20929 $lx1 = $x2;
20930 $lx2 = $x2;
20931 $this->SetLineWidth($Rw);
20932 if ($cort == 'cell' || strpos($tablecorner, 'T') !== false) {
20933 if ($Rw < $Tw) {
20934 $yadj = ($Rw + $Tw) / 2;
20935 }
20936 if ($Rw > $Tw) {
20937 $yadj = ($Rw - $Tw) / 2;
20938 }
20939 } else {
20940 $yadj = $Rw / 2 - $bsv / 2;
20941 }
20942
20943 if ($cort == 'cell' || strpos($tablecorner, 'B') !== false) {
20944 if ($Rw > $Bw) {
20945 $yadj2 = ($Rw - $Bw) / 2;
20946 }
20947 if ($Rw < $Bw) {
20948 $yadj2 = ($Rw + $Bw) / 2;
20949 }
20950 } else {
20951 $yadj2 = $Rw / 2 - $bsv / 2;
20952 }
20953
20954 if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['RT'])) {
20955 $yadj = ($Rw - $details['mbw']['RT']) / 2;
20956 }
20957 if (!$bSeparate && !empty($details['mbw']) && !empty($details['mbw']['RB'])) {
20958 $yadj2 = ($Rw - $details['mbw']['RB']) / 2;
20959 }
20960 $print = true;
20961 }
20962 if ($Bw && $side == 'B' && $this->issetBorder($bord, Border::BOTTOM)) { // BOTTOM
20963 $ly1 = $y2;
20964 $ly2 = $y2;
20965 $lx1 = $x;
20966 $lx2 = $x2;
20967 $this->SetLineWidth($Bw);
20968 if ($cort == 'cell' || strpos($tablecorner, 'L') !== false) {
20969 if ($Bw > $Lw) {
20970 $xadj = ($Bw - $Lw) / 2;
20971 }
20972 if ($Bw < $Lw) {
20973 $xadj = ($Bw + $Lw) / 2;
20974 }
20975 } else {
20976 $xadj = $Bw / 2 - $bsh / 2;
20977 }
20978 if ($cort == 'cell' || strpos($tablecorner, 'R') !== false) {
20979 if ($Bw > $Rw) {
20980 $xadj2 = ($Bw - $Rw) / 2;
20981 }
20982 if ($Bw < $Rw) {
20983 $xadj2 = ($Bw + $Rw) / 2;
20984 }
20985 } else {
20986 $xadj2 = $Bw / 2 - $bsh / 2;
20987 }
20988 if (!$bSeparate && isset($details['mbw']) && isset($details['mbw']['BL'])) {
20989 $xadj = ($Bw - $details['mbw']['BL']) / 2;
20990 }
20991 if (!$bSeparate && isset($details['mbw']) && isset($details['mbw']['BR'])) {
20992 $xadj2 = ($Bw - $details['mbw']['BR']) / 2;
20993 }
20994 $print = true;
20995 }
20996
20997 // Now draw line
20998 if ($print) {
20999 /* -- TABLES-ADVANCED-BORDERS -- */
21000 if ($details[$side]['style'] == 'double') {
21001 if (!isset($details[$side]['overlay']) || !$details[$side]['overlay'] || $bSeparate) {
21002 if ($details[$side]['c']) {
21003 $this->SetDColor($details[$side]['c']);
21004 } else {
21005 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
21006 }
21007 $this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
21008 }
21009 if ((isset($details[$side]['overlay']) && $details[$side]['overlay']) || $bSeparate) {
21010 if ($bSeparate && $cort == 'table') {
21011 if ($side == 'T') {
21012 $xadj -= $this->LineWidth / 2;
21013 $xadj2 -= $this->LineWidth;
21014 if ($this->issetBorder($bord, Border::LEFT)) {
21015 $xadj += $this->LineWidth / 2;
21016 }
21017 if ($this->issetBorder($bord, Border::RIGHT)) {
21018 $xadj2 += $this->LineWidth;
21019 }
21020 }
21021 if ($side == 'L') {
21022 $yadj -= $this->LineWidth / 2;
21023 $yadj2 -= $this->LineWidth;
21024 if ($this->issetBorder($bord, Border::TOP)) {
21025 $yadj += $this->LineWidth / 2;
21026 }
21027 if ($this->issetBorder($bord, Border::BOTTOM)) {
21028 $yadj2 += $this->LineWidth;
21029 }
21030 }
21031 if ($side == 'B') {
21032 $xadj -= $this->LineWidth / 2;
21033 $xadj2 -= $this->LineWidth;
21034 if ($this->issetBorder($bord, Border::LEFT)) {
21035 $xadj += $this->LineWidth / 2;
21036 }
21037 if ($this->issetBorder($bord, Border::RIGHT)) {
21038 $xadj2 += $this->LineWidth;
21039 }
21040 }
21041 if ($side == 'R') {
21042 $yadj -= $this->LineWidth / 2;
21043 $yadj2 -= $this->LineWidth;
21044 if ($this->issetBorder($bord, Border::TOP)) {
21045 $yadj += $this->LineWidth / 2;
21046 }
21047 if ($this->issetBorder($bord, Border::BOTTOM)) {
21048 $yadj2 += $this->LineWidth;
21049 }
21050 }
21051 }
21052
21053 $this->SetLineWidth($this->LineWidth / 3);
21054
21055 $tbcol = $this->colorConverter->convert(255, $this->PDFAXwarnings);
21056 for ($l = 0; $l <= $this->blklvl; $l++) {
21057 if ($this->blk[$l]['bgcolor']) {
21058 $tbcol = ($this->blk[$l]['bgcolorarray']);
21059 }
21060 }
21061
21062 if ($bSeparate) {
21063 $cellBorderOverlay[] = [
21064 'x' => $lx1 + $xadj,
21065 'y' => $ly1 + $yadj,
21066 'x2' => $lx2 - $xadj2,
21067 'y2' => $ly2 - $yadj2,
21068 'col' => $tbcol,
21069 'lw' => $this->LineWidth,
21070 ];
21071 } else {
21072 $this->SetDColor($tbcol);
21073 $this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
21074 }
21075 }
21076 } elseif (isset($details[$side]['style']) && ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'groove' || $details[$side]['style'] == 'inset' || $details[$side]['style'] == 'outset')) {
21077 if (!isset($details[$side]['overlay']) || !$details[$side]['overlay'] || $bSeparate) {
21078 if ($details[$side]['c']) {
21079 $this->SetDColor($details[$side]['c']);
21080 } else {
21081 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
21082 }
21083 if ($details[$side]['style'] == 'outset' || $details[$side]['style'] == 'groove') {
21084 $nc = $this->colorConverter->darken($details[$side]['c']);
21085 $this->SetDColor($nc);
21086 } elseif ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'inset') {
21087 $nc = $this->colorConverter->lighten($details[$side]['c']);
21088 $this->SetDColor($nc);
21089 }
21090 $this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
21091 }
21092 if ((isset($details[$side]['overlay']) && $details[$side]['overlay']) || $bSeparate) {
21093 if ($details[$side]['c']) {
21094 $this->SetDColor($details[$side]['c']);
21095 } else {
21096 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
21097 }
21098 $doubleadj = ($this->LineWidth) / 3;
21099 $this->SetLineWidth($this->LineWidth / 2);
21100 $xadj3 = $yadj3 = $wadj3 = $hadj3 = 0;
21101
21102 if ($details[$side]['style'] == 'ridge' || $details[$side]['style'] == 'inset') {
21103 $nc = $this->colorConverter->darken($details[$side]['c']);
21104
21105 if ($bSeparate && $cort == 'table') {
21106 if ($side == 'T') {
21107 $yadj3 = $this->LineWidth / 2;
21108 $xadj3 = -$this->LineWidth / 2;
21109 $wadj3 = $this->LineWidth;
21110 if ($this->issetBorder($bord, Border::LEFT)) {
21111 $xadj3 += $this->LineWidth;
21112 $wadj3 -= $this->LineWidth;
21113 }
21114 if ($this->issetBorder($bord, Border::RIGHT)) {
21115 $wadj3 -= $this->LineWidth * 2;
21116 }
21117 }
21118 if ($side == 'L') {
21119 $xadj3 = $this->LineWidth / 2;
21120 $yadj3 = -$this->LineWidth / 2;
21121 $hadj3 = $this->LineWidth;
21122 if ($this->issetBorder($bord, Border::TOP)) {
21123 $yadj3 += $this->LineWidth;
21124 $hadj3 -= $this->LineWidth;
21125 }
21126 if ($this->issetBorder($bord, Border::BOTTOM)) {
21127 $hadj3 -= $this->LineWidth * 2;
21128 }
21129 }
21130 if ($side == 'B') {
21131 $yadj3 = $this->LineWidth / 2;
21132 $xadj3 = -$this->LineWidth / 2;
21133 $wadj3 = $this->LineWidth;
21134 }
21135 if ($side == 'R') {
21136 $xadj3 = $this->LineWidth / 2;
21137 $yadj3 = -$this->LineWidth / 2;
21138 $hadj3 = $this->LineWidth;
21139 }
21140 } elseif ($side == 'T') {
21141 $yadj3 = $this->LineWidth / 2;
21142 $xadj3 = $this->LineWidth / 2;
21143 $wadj3 = -$this->LineWidth * 2;
21144 } elseif ($side == 'L') {
21145 $xadj3 = $this->LineWidth / 2;
21146 $yadj3 = $this->LineWidth / 2;
21147 $hadj3 = -$this->LineWidth * 2;
21148 } elseif ($side == 'B' && $bSeparate) {
21149 $yadj3 = $this->LineWidth / 2;
21150 $wadj3 = $this->LineWidth / 2;
21151 } elseif ($side == 'R' && $bSeparate) {
21152 $xadj3 = $this->LineWidth / 2;
21153 $hadj3 = $this->LineWidth / 2;
21154 } elseif ($side == 'B') {
21155 $yadj3 = $this->LineWidth / 2;
21156 $xadj3 = $this->LineWidth / 2;
21157 } elseif ($side == 'R') {
21158 $xadj3 = $this->LineWidth / 2;
21159 $yadj3 = $this->LineWidth / 2;
21160 }
21161 } else {
21162 $nc = $this->colorConverter->lighten($details[$side]['c']);
21163
21164 if ($bSeparate && $cort == 'table') {
21165 if ($side == 'T') {
21166 $yadj3 = $this->LineWidth / 2;
21167 $xadj3 = -$this->LineWidth / 2;
21168 $wadj3 = $this->LineWidth;
21169 if ($this->issetBorder($bord, Border::LEFT)) {
21170 $xadj3 += $this->LineWidth;
21171 $wadj3 -= $this->LineWidth;
21172 }
21173 }
21174 if ($side == 'L') {
21175 $xadj3 = $this->LineWidth / 2;
21176 $yadj3 = -$this->LineWidth / 2;
21177 $hadj3 = $this->LineWidth;
21178 if ($this->issetBorder($bord, Border::TOP)) {
21179 $yadj3 += $this->LineWidth;
21180 $hadj3 -= $this->LineWidth;
21181 }
21182 }
21183 if ($side == 'B') {
21184 $yadj3 = $this->LineWidth / 2;
21185 $xadj3 = -$this->LineWidth / 2;
21186 $wadj3 = $this->LineWidth;
21187 if ($this->issetBorder($bord, Border::LEFT)) {
21188 $xadj3 += $this->LineWidth;
21189 $wadj3 -= $this->LineWidth;
21190 }
21191 }
21192 if ($side == 'R') {
21193 $xadj3 = $this->LineWidth / 2;
21194 $yadj3 = -$this->LineWidth / 2;
21195 $hadj3 = $this->LineWidth;
21196 if ($this->issetBorder($bord, Border::TOP)) {
21197 $yadj3 += $this->LineWidth;
21198 $hadj3 -= $this->LineWidth;
21199 }
21200 }
21201 } elseif ($side == 'T') {
21202 $yadj3 = $this->LineWidth / 2;
21203 $xadj3 = $this->LineWidth / 2;
21204 } elseif ($side == 'L') {
21205 $xadj3 = $this->LineWidth / 2;
21206 $yadj3 = $this->LineWidth / 2;
21207 } elseif ($side == 'B' && $bSeparate) {
21208 $yadj3 = $this->LineWidth / 2;
21209 $xadj3 = $this->LineWidth / 2;
21210 } elseif ($side == 'R' && $bSeparate) {
21211 $xadj3 = $this->LineWidth / 2;
21212 $yadj3 = $this->LineWidth / 2;
21213 } elseif ($side == 'B') {
21214 $yadj3 = $this->LineWidth / 2;
21215 $xadj3 = -$this->LineWidth / 2;
21216 $wadj3 = $this->LineWidth;
21217 } elseif ($side == 'R') {
21218 $xadj3 = $this->LineWidth / 2;
21219 $yadj3 = -$this->LineWidth / 2;
21220 $hadj3 = $this->LineWidth;
21221 }
21222 }
21223
21224 if ($bSeparate) {
21225 $cellBorderOverlay[] = [
21226 'x' => $lx1 + $xadj + $xadj3,
21227 'y' => $ly1 + $yadj + $yadj3,
21228 'x2' => $lx2 - $xadj2 + $xadj3 + $wadj3,
21229 'y2' => $ly2 - $yadj2 + $yadj3 + $hadj3,
21230 'col' => $nc,
21231 'lw' => $this->LineWidth,
21232 ];
21233 } else {
21234 $this->SetDColor($nc);
21235 $this->Line($lx1 + $xadj + $xadj3, $ly1 + $yadj + $yadj3, $lx2 - $xadj2 + $xadj3 + $wadj3, $ly2 - $yadj2 + $yadj3 + $hadj3);
21236 }
21237 }
21238 } else {
21239 /* -- END TABLES-ADVANCED-BORDERS -- */
21240 if ($details[$side]['style'] == 'dashed') {
21241 $dashsize = 2; // final dash will be this + 1*linewidth
21242 $dashsizek = 1.5; // ratio of Dash/Blank
21243 $this->SetDash($dashsize, ($dashsize / $dashsizek) + ($this->LineWidth * 2));
21244 } elseif ($details[$side]['style'] == 'dotted') {
21245 $this->SetLineJoin(1);
21246 $this->SetLineCap(1);
21247 $this->SetDash(0.001, ($this->LineWidth * 2));
21248 }
21249 if ($details[$side]['c']) {
21250 $this->SetDColor($details[$side]['c']);
21251 } else {
21252 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
21253 }
21254 $this->Line($lx1 + $xadj, $ly1 + $yadj, $lx2 - $xadj2, $ly2 - $yadj2);
21255 /* -- TABLES-ADVANCED-BORDERS -- */
21256 }
21257 /* -- END TABLES-ADVANCED-BORDERS -- */
21258
21259 // Reset Corners
21260 $this->SetDash();
21261 // BUTT style line cap
21262 $this->SetLineCap(2);
21263 }
21264 }
21265
21266 if ($bSeparate && count($cellBorderOverlay)) {
21267 foreach ($cellBorderOverlay as $cbo) {
21268 $this->SetLineWidth($cbo['lw']);
21269 $this->SetDColor($cbo['col']);
21270 $this->Line($cbo['x'], $cbo['y'], $cbo['x2'], $cbo['y2']);
21271 }
21272 }
21273
21274 // $this->SetLineWidth($oldlinewidth);
21275 // $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
21276 }
21277 }
21278
21279 /* -- TABLES -- */
21280 /* -- TABLES-ADVANCED-BORDERS -- */
21281
21282 /* -- END TABLES-ADVANCED-BORDERS -- */
21283
21284 function setBorder(&$var, $flag, $set = true)
21285 {
21286 $flag = intval($flag);
21287 if ($set) {
21288 $set = true;
21289 }
21290 $var = intval($var);
21291 $var = $set ? ($var | $flag) : ($var & ~$flag);
21292 }
21293
21294 function issetBorder($var, $flag)
21295 {
21296 $flag = intval($flag);
21297 $var = intval($var);
21298 return (($var & $flag) == $flag);
21299 }
21300
21301 function _table2cellBorder(&$tableb, &$cbdb, &$cellb, $bval)
21302 {
21303 if ($tableb && $tableb['w'] > $cbdb['w']) {
21304 $cbdb = $tableb;
21305 $this->setBorder($cellb, $bval);
21306 } elseif ($tableb && $tableb['w'] == $cbdb['w'] && array_search($tableb['style'], $this->borderstyles) > array_search($cbdb['style'], $this->borderstyles)) {
21307 $cbdb = $tableb;
21308 $this->setBorder($cellb, $bval);
21309 }
21310 }
21311
21312 // FIX BORDERS ********************************************
21313 function _fixTableBorders(&$table)
21314 {
21315 if (!$table['borders_separate'] && $table['border_details']['L']['w']) {
21316 $table['max_cell_border_width']['L'] = $table['border_details']['L']['w'];
21317 }
21318 if (!$table['borders_separate'] && $table['border_details']['R']['w']) {
21319 $table['max_cell_border_width']['R'] = $table['border_details']['R']['w'];
21320 }
21321 if (!$table['borders_separate'] && $table['border_details']['T']['w']) {
21322 $table['max_cell_border_width']['T'] = $table['border_details']['T']['w'];
21323 }
21324 if (!$table['borders_separate'] && $table['border_details']['B']['w']) {
21325 $table['max_cell_border_width']['B'] = $table['border_details']['B']['w'];
21326 }
21327 if ($this->simpleTables) {
21328 return;
21329 }
21330 $cells = &$table['cells'];
21331 $numcols = $table['nc'];
21332 $numrows = $table['nr'];
21333 /* -- TABLES-ADVANCED-BORDERS -- */
21334 if (isset($table['topntail']) && $table['topntail']) {
21335 $tntborddet = $this->border_details($table['topntail']);
21336 }
21337 if (isset($table['thead-underline']) && $table['thead-underline']) {
21338 $thuborddet = $this->border_details($table['thead-underline']);
21339 }
21340 /* -- END TABLES-ADVANCED-BORDERS -- */
21341
21342 for ($i = 0; $i < $numrows; $i++) { // Rows
21343 for ($j = 0; $j < $numcols; $j++) { // Columns
21344 if (isset($cells[$i][$j]) && $cells[$i][$j]) {
21345 $cell = &$cells[$i][$j];
21346 if ($this->packTableData) {
21347 $cbord = $this->_unpackCellBorder($cell['borderbin']);
21348 } else {
21349 $cbord = &$cells[$i][$j];
21350 }
21351
21352 // mPDF 5.7.3
21353 if (!$cbord['border'] && $cbord['border'] !== 0 && isset($table['border']) && $table['border'] && $this->table_border_attr_set) {
21354 $cbord['border'] = $table['border'];
21355 $cbord['border_details'] = $table['border_details'];
21356 }
21357
21358 if (isset($cell['colspan']) && $cell['colspan'] > 1) {
21359 $ccolsp = $cell['colspan'];
21360 } else {
21361 $ccolsp = 1;
21362 }
21363 if (isset($cell['rowspan']) && $cell['rowspan'] > 1) {
21364 $crowsp = $cell['rowspan'];
21365 } else {
21366 $crowsp = 1;
21367 }
21368
21369 $cbord['border_details']['cellposdom'] = ((($i + 1) / $numrows) / 10000 ) + ((($j + 1) / $numcols) / 10 );
21370 // Inherit Cell border from Table border
21371 if ($this->table_border_css_set && !$table['borders_separate']) {
21372 if ($i == 0) {
21373 $this->_table2cellBorder($table['border_details']['T'], $cbord['border_details']['T'], $cbord['border'], Border::TOP);
21374 }
21375 if ($i == ($numrows - 1) || ($i + $crowsp) == ($numrows)) {
21376 $this->_table2cellBorder($table['border_details']['B'], $cbord['border_details']['B'], $cbord['border'], Border::BOTTOM);
21377 }
21378 if ($j == 0) {
21379 $this->_table2cellBorder($table['border_details']['L'], $cbord['border_details']['L'], $cbord['border'], Border::LEFT);
21380 }
21381 if ($j == ($numcols - 1) || ($j + $ccolsp) == ($numcols)) {
21382 $this->_table2cellBorder($table['border_details']['R'], $cbord['border_details']['R'], $cbord['border'], Border::RIGHT);
21383 }
21384 }
21385
21386 /* -- TABLES-ADVANCED-BORDERS -- */
21387 $fixbottom = true;
21388 if (isset($table['topntail']) && $table['topntail']) {
21389 if ($i == 0) {
21390 $cbord['border_details']['T'] = $tntborddet;
21391 $this->setBorder($cbord['border'], Border::TOP);
21392 }
21393 if ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows'] - 1) {
21394 $cbord['border_details']['B'] = $tntborddet;
21395 $this->setBorder($cbord['border'], Border::BOTTOM);
21396 $fixbottom = false;
21397 } elseif ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows']) {
21398 if (!$table['borders_separate']) {
21399 $cbord['border_details']['T'] = $tntborddet;
21400 $this->setBorder($cbord['border'], Border::TOP);
21401 }
21402 }
21403 if ($this->tableLevel == 1 && $table['footernrows'] > 0 && $i == ($numrows - $table['footernrows'] - 1)) {
21404 if (!$table['borders_separate']) {
21405 $cbord['border_details']['B'] = $tntborddet;
21406 $this->setBorder($cbord['border'], Border::BOTTOM);
21407 $fixbottom = false;
21408 }
21409 } elseif ($this->tableLevel == 1 && $table['footernrows'] > 0 && $i == ($numrows - $table['footernrows'])) {
21410 $cbord['border_details']['T'] = $tntborddet;
21411 $this->setBorder($cbord['border'], Border::TOP);
21412 }
21413 if ($this->tabletheadjustfinished) { // $this->tabletheadjustfinished called from tableheader
21414 if (!$table['borders_separate']) {
21415 $cbord['border_details']['T'] = $tntborddet;
21416 $this->setBorder($cbord['border'], Border::TOP);
21417 }
21418 }
21419 if ($i == ($numrows - 1) || ($i + $crowsp) == ($numrows)) {
21420 $cbord['border_details']['B'] = $tntborddet;
21421 $this->setBorder($cbord['border'], Border::BOTTOM);
21422 }
21423 }
21424 if (isset($table['thead-underline']) && $table['thead-underline']) {
21425 if ($table['borders_separate']) {
21426 if ($i == 0) {
21427 $cbord['border_details']['B'] = $thuborddet;
21428 $this->setBorder($cbord['border'], Border::BOTTOM);
21429 $fixbottom = false;
21430 }
21431 } else {
21432 if ($this->tableLevel == 1 && $table['headernrows'] > 0 && $i == $table['headernrows'] - 1) {
21433 $cbord['border_details']['T'] = $thuborddet;
21434 $this->setBorder($cbord['border'], Border::TOP);
21435 } elseif ($this->tabletheadjustfinished) { // $this->tabletheadjustfinished called from tableheader
21436 $cbord['border_details']['T'] = $thuborddet;
21437 $this->setBorder($cbord['border'], Border::TOP);
21438 }
21439 }
21440 }
21441
21442 // Collapse Border - Algorithm for conflicting borders
21443 // Hidden >> Width >> double>solid>dashed>dotted... >> style set on cell>table >> top/left>bottom/right
21444 // Do not turn off border which is overridden
21445 // Needed for page break for TOP/BOTTOM both to be defined in Collapsed borders
21446 // Means it is painted twice. (Left/Right can still disable overridden border)
21447 if (!$table['borders_separate']) {
21448
21449 if (($i < ($numrows - 1) || ($i + $crowsp) < $numrows ) && $fixbottom) { // Bottom
21450
21451 for ($cspi = 0; $cspi < $ccolsp; $cspi++) {
21452
21453 // already defined Top for adjacent cell below
21454 if (isset($cells[($i + $crowsp)][$j + $cspi])) {
21455 if ($this->packTableData) {
21456 $adjc = $cells[($i + $crowsp)][$j + $cspi];
21457 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
21458 } else {
21459 $celladj = & $cells[($i + $crowsp)][$j + $cspi];
21460 }
21461 } else {
21462 $celladj = false;
21463 }
21464
21465 if (isset($celladj['border_details']['T']['s']) && $celladj['border_details']['T']['s'] == 1) {
21466
21467 $csadj = $celladj['border_details']['T']['w'];
21468 $csthis = $cbord['border_details']['B']['w'];
21469
21470 // Hidden
21471 if ($cbord['border_details']['B']['style'] == 'hidden') {
21472
21473 $celladj['border_details']['T'] = $cbord['border_details']['B'];
21474 $this->setBorder($celladj['border'], Border::TOP, false);
21475 $this->setBorder($cbord['border'], Border::BOTTOM, false);
21476
21477 } elseif ($celladj['border_details']['T']['style'] == 'hidden') {
21478
21479 $cbord['border_details']['B'] = $celladj['border_details']['T'];
21480 $this->setBorder($cbord['border'], Border::BOTTOM, false);
21481 $this->setBorder($celladj['border'], Border::TOP, false);
21482
21483 } elseif ($csthis > $csadj) { // Width
21484
21485 if (!isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) || (isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) && $cells[($i + $crowsp)][$j + $cspi]['colspan'] < 2)) { // don't overwrite bordering cells that span
21486 $celladj['border_details']['T'] = $cbord['border_details']['B'];
21487 $this->setBorder($cbord['border'], Border::BOTTOM);
21488 }
21489
21490 } elseif ($csadj > $csthis) {
21491
21492 if ($ccolsp < 2) { // don't overwrite this cell if it spans
21493 $cbord['border_details']['B'] = $celladj['border_details']['T'];
21494 $this->setBorder($celladj['border'], Border::TOP);
21495 }
21496
21497 } elseif (array_search($cbord['border_details']['B']['style'], $this->borderstyles) > array_search($celladj['border_details']['T']['style'], $this->borderstyles)) { // double>solid>dashed>dotted...
21498
21499 if (!isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) || (isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) && $cells[($i + $crowsp)][$j + $cspi]['colspan'] < 2)) { // don't overwrite bordering cells that span
21500 $celladj['border_details']['T'] = $cbord['border_details']['B'];
21501 $this->setBorder($cbord['border'], Border::BOTTOM);
21502 }
21503
21504 } elseif (array_search($celladj['border_details']['T']['style'], $this->borderstyles) > array_search($cbord['border_details']['B']['style'], $this->borderstyles)) {
21505
21506 if ($ccolsp < 2) { // don't overwrite this cell if it spans
21507 $cbord['border_details']['B'] = $celladj['border_details']['T'];
21508 $this->setBorder($celladj['border'], Border::TOP);
21509 }
21510
21511 } elseif ($celladj['border_details']['T']['dom'] > $celladj['border_details']['B']['dom']) { // Style set on cell vs. table
21512
21513 if ($ccolsp < 2) { // don't overwrite this cell if it spans
21514 $cbord['border_details']['B'] = $celladj['border_details']['T'];
21515 $this->setBorder($celladj['border'], Border::TOP);
21516 }
21517
21518 } else { // Style set on cell vs. table - OR - LEFT/TOP (cell) in preference to BOTTOM/RIGHT
21519
21520 if (!isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) || (isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) && $cells[($i + $crowsp)][$j + $cspi]['colspan'] < 2)) { // don't overwrite bordering cells that span
21521 $celladj['border_details']['T'] = $cbord['border_details']['B'];
21522 $this->setBorder($cbord['border'], Border::BOTTOM);
21523 }
21524
21525 }
21526
21527 } elseif ($celladj) {
21528
21529 if (!isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) || (isset($cells[($i + $crowsp)][$j + $cspi]['colspan']) && $cells[($i + $crowsp)][$j + $cspi]['colspan'] < 2)) { // don't overwrite bordering cells that span
21530 $celladj['border_details']['T'] = $cbord['border_details']['B'];
21531 }
21532
21533 }
21534
21535 // mPDF 5.7.4
21536 if ($celladj && $this->packTableData) {
21537 $cells[$i + $crowsp][$j + $cspi]['borderbin'] = $this->_packCellBorder($celladj);
21538 }
21539
21540 unset($celladj);
21541 }
21542 }
21543
21544 if ($j < ($numcols - 1) || ($j + $ccolsp) < $numcols) { // Right-Left
21545
21546 for ($cspi = 0; $cspi < $crowsp; $cspi++) {
21547
21548 // already defined Left for adjacent cell to R
21549 if (isset($cells[($i + $cspi)][$j + $ccolsp])) {
21550 if ($this->packTableData) {
21551 $adjc = $cells[($i + $cspi)][$j + $ccolsp];
21552 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
21553 } else {
21554 $celladj = & $cells[$i + $cspi][$j + $ccolsp];
21555 }
21556 } else {
21557 $celladj = false;
21558 }
21559 if ($celladj && $celladj['border_details']['L']['s'] == 1) {
21560 $csadj = $celladj['border_details']['L']['w'];
21561 $csthis = $cbord['border_details']['R']['w'];
21562 // Hidden
21563 if ($cbord['border_details']['R']['style'] == 'hidden') {
21564 $celladj['border_details']['L'] = $cbord['border_details']['R'];
21565 $this->setBorder($celladj['border'], Border::LEFT, false);
21566 $this->setBorder($cbord['border'], Border::RIGHT, false);
21567 } elseif ($celladj['border_details']['L']['style'] == 'hidden') {
21568 $cbord['border_details']['R'] = $celladj['border_details']['L'];
21569 $this->setBorder($cbord['border'], Border::RIGHT, false);
21570 $this->setBorder($celladj['border'], Border::LEFT, false);
21571 } // Width
21572 elseif ($csthis > $csadj) {
21573 if (!isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) || (isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) && $cells[($i + $cspi)][$j + $ccolsp]['rowspan'] < 2)) { // don't overwrite bordering cells that span
21574 $celladj['border_details']['L'] = $cbord['border_details']['R'];
21575 $this->setBorder($cbord['border'], Border::RIGHT);
21576 $this->setBorder($celladj['border'], Border::LEFT, false);
21577 }
21578 } elseif ($csadj > $csthis) {
21579 if ($crowsp < 2) { // don't overwrite this cell if it spans
21580 $cbord['border_details']['R'] = $celladj['border_details']['L'];
21581 $this->setBorder($cbord['border'], Border::RIGHT, false);
21582 $this->setBorder($celladj['border'], Border::LEFT);
21583 }
21584 } // double>solid>dashed>dotted...
21585 elseif (array_search($cbord['border_details']['R']['style'], $this->borderstyles) > array_search($celladj['border_details']['L']['style'], $this->borderstyles)) {
21586 if (!isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) || (isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) && $cells[($i + $cspi)][$j + $ccolsp]['rowspan'] < 2)) { // don't overwrite bordering cells that span
21587 $celladj['border_details']['L'] = $cbord['border_details']['R'];
21588 $this->setBorder($celladj['border'], Border::LEFT, false);
21589 $this->setBorder($cbord['border'], Border::RIGHT);
21590 }
21591 } elseif (array_search($celladj['border_details']['L']['style'], $this->borderstyles) > array_search($cbord['border_details']['R']['style'], $this->borderstyles)) {
21592 if ($crowsp < 2) { // don't overwrite this cell if it spans
21593 $cbord['border_details']['R'] = $celladj['border_details']['L'];
21594 $this->setBorder($cbord['border'], Border::RIGHT, false);
21595 $this->setBorder($celladj['border'], Border::LEFT);
21596 }
21597 } // Style set on cell vs. table
21598 elseif ($celladj['border_details']['L']['dom'] > $cbord['border_details']['R']['dom']) {
21599 if ($crowsp < 2) { // don't overwrite this cell if it spans
21600 $cbord['border_details']['R'] = $celladj['border_details']['L'];
21601 $this->setBorder($celladj['border'], Border::LEFT);
21602 }
21603 } // Style set on cell vs. table - OR - LEFT/TOP (cell) in preference to BOTTOM/RIGHT
21604 else {
21605 if (!isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) || (isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) && $cells[($i + $cspi)][$j + $ccolsp]['rowspan'] < 2)) { // don't overwrite bordering cells that span
21606 $celladj['border_details']['L'] = $cbord['border_details']['R'];
21607 $this->setBorder($cbord['border'], Border::RIGHT);
21608 }
21609 }
21610 } elseif ($celladj) {
21611 // if right-cell border is not set
21612 if (!isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) || (isset($cells[($i + $cspi)][$j + $ccolsp]['rowspan']) && $cells[($i + $cspi)][$j + $ccolsp]['rowspan'] < 2)) { // don't overwrite bordering cells that span
21613 $celladj['border_details']['L'] = $cbord['border_details']['R'];
21614 }
21615 }
21616 // mPDF 5.7.4
21617 if ($celladj && $this->packTableData) {
21618 $cells[$i + $cspi][$j + $ccolsp]['borderbin'] = $this->_packCellBorder($celladj);
21619 }
21620 unset($celladj);
21621 }
21622 }
21623 }
21624
21625
21626 // Set maximum cell border width meeting at LRTB edges of cell - used for extended cell border
21627 // ['border_details']['mbw']['LT'] = meeting border width - Left border - Top end
21628 if (!$table['borders_separate']) {
21629
21630 $cbord['border_details']['mbw']['BL'] = max($cbord['border_details']['mbw']['BL'], $cbord['border_details']['L']['w']);
21631 $cbord['border_details']['mbw']['BR'] = max($cbord['border_details']['mbw']['BR'], $cbord['border_details']['R']['w']);
21632 $cbord['border_details']['mbw']['RT'] = max($cbord['border_details']['mbw']['RT'], $cbord['border_details']['T']['w']);
21633 $cbord['border_details']['mbw']['RB'] = max($cbord['border_details']['mbw']['RB'], $cbord['border_details']['B']['w']);
21634 $cbord['border_details']['mbw']['TL'] = max($cbord['border_details']['mbw']['TL'], $cbord['border_details']['L']['w']);
21635 $cbord['border_details']['mbw']['TR'] = max($cbord['border_details']['mbw']['TR'], $cbord['border_details']['R']['w']);
21636 $cbord['border_details']['mbw']['LT'] = max($cbord['border_details']['mbw']['LT'], $cbord['border_details']['T']['w']);
21637 $cbord['border_details']['mbw']['LB'] = max($cbord['border_details']['mbw']['LB'], $cbord['border_details']['B']['w']);
21638
21639 if (($i + $crowsp) < $numrows && isset($cells[$i + $crowsp][$j])) { // Has Bottom adjoining cell
21640
21641 if ($this->packTableData) {
21642 $adjc = $cells[$i + $crowsp][$j];
21643 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
21644 } else {
21645 $celladj = & $cells[$i + $crowsp][$j];
21646 }
21647
21648 $cbord['border_details']['mbw']['BL'] = max(
21649 $cbord['border_details']['mbw']['BL'],
21650 $celladj ? $celladj['border_details']['L']['w'] : 0,
21651 $celladj ? $celladj['border_details']['mbw']['TL']: 0
21652 );
21653
21654 $cbord['border_details']['mbw']['BR'] = max(
21655 $cbord['border_details']['mbw']['BR'],
21656 $celladj ? $celladj['border_details']['R']['w'] : 0,
21657 $celladj ? $celladj['border_details']['mbw']['TR']: 0
21658 );
21659
21660 $cbord['border_details']['mbw']['LB'] = max(
21661 $cbord['border_details']['mbw']['LB'],
21662 $celladj ? $celladj['border_details']['mbw']['LT'] : 0
21663 );
21664
21665 $cbord['border_details']['mbw']['RB'] = max(
21666 $cbord['border_details']['mbw']['RB'],
21667 $celladj ? $celladj['border_details']['mbw']['RT'] : 0
21668 );
21669
21670 unset($celladj);
21671 }
21672
21673 if (($j + $ccolsp) < $numcols && isset($cells[$i][$j + $ccolsp])) { // Has Right adjoining cell
21674
21675 if ($this->packTableData) {
21676 $adjc = $cells[$i][$j + $ccolsp];
21677 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
21678 } else {
21679 $celladj = & $cells[$i][$j + $ccolsp];
21680 }
21681
21682 $cbord['border_details']['mbw']['RT'] = max(
21683 $cbord['border_details']['mbw']['RT'],
21684 $celladj ? $celladj['border_details']['T']['w'] : 0,
21685 $celladj ? $celladj['border_details']['mbw']['LT'] : 0
21686 );
21687
21688 $cbord['border_details']['mbw']['RB'] = max(
21689 $cbord['border_details']['mbw']['RB'],
21690 $celladj ? $celladj['border_details']['B']['w'] : 0,
21691 $celladj ? $celladj['border_details']['mbw']['LB'] : 0
21692 );
21693
21694 $cbord['border_details']['mbw']['TR'] = max(
21695 $cbord['border_details']['mbw']['TR'],
21696 $celladj ? $celladj['border_details']['mbw']['TL'] : 0
21697 );
21698
21699 $cbord['border_details']['mbw']['BR'] = max(
21700 $cbord['border_details']['mbw']['BR'],
21701 $celladj ? $celladj['border_details']['mbw']['BL'] : 0
21702 );
21703
21704 unset($celladj);
21705 }
21706
21707 if ($i > 0 && isset($cells[$i - 1][$j]) && is_array($cells[$i - 1][$j]) && (($this->packTableData && $cells[$i - 1][$j]['borderbin']) || $cells[$i - 1][$j]['border'])) { // Has Top adjoining cell
21708
21709 if ($this->packTableData) {
21710 $adjc = $cells[$i - 1][$j];
21711 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
21712 } else {
21713 $celladj = & $cells[$i - 1][$j];
21714 }
21715
21716 $cbord['border_details']['mbw']['TL'] = max(
21717 $cbord['border_details']['mbw']['TL'],
21718 $celladj ? $celladj['border_details']['L']['w'] : 0,
21719 $celladj ? $celladj['border_details']['mbw']['BL'] : 0
21720 );
21721
21722 $cbord['border_details']['mbw']['TR'] = max(
21723 $cbord['border_details']['mbw']['TR'],
21724 $celladj ? $celladj['border_details']['R']['w'] : 0,
21725 $celladj ? $celladj['border_details']['mbw']['BR'] : 0
21726 );
21727
21728 $cbord['border_details']['mbw']['LT'] = max(
21729 $cbord['border_details']['mbw']['LT'],
21730 $celladj ? $celladj['border_details']['mbw']['LB'] : 0
21731 );
21732
21733 $cbord['border_details']['mbw']['RT'] = max(
21734 $cbord['border_details']['mbw']['RT'],
21735 $celladj ? $celladj['border_details']['mbw']['RB'] : 0
21736 );
21737
21738 if ($celladj['border_details']['mbw']['BL']) {
21739 $celladj['border_details']['mbw']['BL'] = max($cbord['border_details']['mbw']['TL'], $celladj['border_details']['mbw']['BL']);
21740 }
21741
21742 if ($celladj['border_details']['mbw']['BR']) {
21743 $celladj['border_details']['mbw']['BR'] = max($celladj['border_details']['mbw']['BR'], $cbord['border_details']['mbw']['TR']);
21744 }
21745
21746 if ($this->packTableData) {
21747 $cells[$i - 1][$j]['borderbin'] = $this->_packCellBorder($celladj);
21748 }
21749 unset($celladj);
21750 }
21751
21752 if ($j > 0 && isset($cells[$i][$j - 1]) && is_array($cells[$i][$j - 1]) && (($this->packTableData && $cells[$i][$j - 1]['borderbin']) || $cells[$i][$j - 1]['border'])) { // Has Left adjoining cell
21753
21754 if ($this->packTableData) {
21755 $adjc = $cells[$i][$j - 1];
21756 $celladj = $this->_unpackCellBorder($adjc['borderbin']);
21757 } else {
21758 $celladj = & $cells[$i][$j - 1];
21759 }
21760
21761 $cbord['border_details']['mbw']['LT'] = max(
21762 $cbord['border_details']['mbw']['LT'],
21763 $celladj ? $celladj['border_details']['T']['w'] : 0,
21764 $celladj ? $celladj['border_details']['mbw']['RT'] : 0
21765 );
21766
21767 $cbord['border_details']['mbw']['LB'] = max(
21768 $cbord['border_details']['mbw']['LB'],
21769 $celladj ? $celladj['border_details']['B']['w'] : 0,
21770 $celladj ? $celladj['border_details']['mbw']['RB'] : 0
21771 );
21772
21773 $cbord['border_details']['mbw']['BL'] = max(
21774 $cbord['border_details']['mbw']['BL'],
21775 $celladj ? $celladj['border_details']['mbw']['BR'] : 0
21776 );
21777
21778 $cbord['border_details']['mbw']['TL'] = max(
21779 $cbord['border_details']['mbw']['TL'],
21780 $celladj ? $celladj['border_details']['mbw']['TR'] : 0
21781 );
21782
21783 if ($celladj['border_details']['mbw']['RT']) {
21784 $celladj['border_details']['mbw']['RT'] = max($celladj['border_details']['mbw']['RT'], $cbord['border_details']['mbw']['LT']);
21785 }
21786
21787 if ($celladj['border_details']['mbw']['RB']) {
21788 $celladj['border_details']['mbw']['RB'] = max($celladj['border_details']['mbw']['RB'], $cbord['border_details']['mbw']['LB']);
21789 }
21790
21791 if ($this->packTableData) {
21792 $cells[$i][$j - 1]['borderbin'] = $this->_packCellBorder($celladj);
21793 }
21794
21795 unset($celladj);
21796 }
21797
21798
21799 // Update maximum cell border width at LRTB edges of table - used for overall table width
21800 if ($j == 0 && $cbord['border_details']['L']['w']) {
21801 $table['max_cell_border_width']['L'] = max($table['max_cell_border_width']['L'], $cbord['border_details']['L']['w']);
21802 }
21803 if (($j == ($numcols - 1) || ($j + $ccolsp) == $numcols ) && $cbord['border_details']['R']['w']) {
21804 $table['max_cell_border_width']['R'] = max($table['max_cell_border_width']['R'], $cbord['border_details']['R']['w']);
21805 }
21806 if ($i == 0 && $cbord['border_details']['T']['w']) {
21807 $table['max_cell_border_width']['T'] = max($table['max_cell_border_width']['T'], $cbord['border_details']['T']['w']);
21808 }
21809 if (($i == ($numrows - 1) || ($i + $crowsp) == $numrows ) && $cbord['border_details']['B']['w']) {
21810 $table['max_cell_border_width']['B'] = max($table['max_cell_border_width']['B'], $cbord['border_details']['B']['w']);
21811 }
21812 }
21813 /* -- END TABLES-ADVANCED-BORDERS -- */
21814
21815 if ($this->packTableData) {
21816 $cell['borderbin'] = $this->_packCellBorder($cbord);
21817 }
21818
21819 unset($cbord);
21820
21821 unset($cell);
21822 }
21823 }
21824 }
21825 unset($cell);
21826 }
21827
21828 // END FIX BORDERS ************************************************************************************
21829
21830 function _reverseTableDir(&$table)
21831 {
21832 $cells = &$table['cells'];
21833 $numcols = $table['nc'];
21834 $numrows = $table['nr'];
21835 for ($i = 0; $i < $numrows; $i++) { // Rows
21836 $row = [];
21837 for ($j = ($numcols - 1); $j >= 0; $j--) { // Columns
21838 if (isset($cells[$i][$j]) && $cells[$i][$j]) {
21839 $cell = &$cells[$i][$j];
21840 $col = $numcols - $j - 1;
21841 if (isset($cell['colspan']) && $cell['colspan'] > 1) {
21842 $col -= ($cell['colspan'] - 1);
21843 }
21844 // Nested content
21845 if (isset($cell['textbuffer'])) {
21846 for ($n = 0; $n < count($cell['textbuffer']); $n++) {
21847 $t = $cell['textbuffer'][$n][0];
21848 if (substr($t, 0, 19) == "\xbb\xa4\xactype=nestedtable") {
21849 $objattr = $this->_getObjAttr($t);
21850 $objattr['col'] = $col;
21851 $cell['textbuffer'][$n][0] = "\xbb\xa4\xactype=nestedtable,objattr=" . serialize($objattr) . "\xbb\xa4\xac";
21852 $this->table[($this->tableLevel + 1)][$objattr['nestedcontent']]['nestedpos'][1] = $col;
21853 }
21854 }
21855 }
21856 $row[$col] = $cells[$i][$j];
21857 unset($cell);
21858 }
21859 }
21860 for ($f = 0; $f < $numcols; $f++) {
21861 if (!isset($row[$f])) {
21862 $row[$f] = 0;
21863 }
21864 }
21865 $table['cells'][$i] = $row;
21866 }
21867 }
21868
21869 function _tableWrite(&$table, $split = false, $startrow = 0, $startcol = 0, $splitpg = 0, $rety = 0)
21870 {
21871 $level = $table['level'];
21872 $levelid = $table['levelid'];
21873
21874 $cells = &$table['cells'];
21875 $numcols = $table['nc'];
21876 $numrows = $table['nr'];
21877 $maxbwtop = 0;
21878 if ($this->ColActive && $level == 1) {
21879 $this->breakpoints[$this->CurrCol][] = $this->y;
21880 } // *COLUMNS*
21881
21882 if (!$split || ($startrow == 0 && $splitpg == 0) || $startrow > 0) {
21883 // TABLE TOP MARGIN
21884 if ($table['margin']['T']) {
21885 if (!$this->table_rotate && $level == 1) {
21886 $this->DivLn($table['margin']['T'], $this->blklvl, true, 1); // collapsible
21887 } else {
21888 $this->y += ($table['margin']['T']);
21889 }
21890 }
21891 // Advance down page by half width of top border
21892 if ($table['borders_separate']) {
21893 if ($startrow > 0 && (!isset($table['is_thead']) || count($table['is_thead']) == 0)) {
21894 $adv = $table['border_spacing_V'] / 2;
21895 } else {
21896 $adv = $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
21897 }
21898 } else {
21899 $adv = $table['max_cell_border_width']['T'] / 2;
21900 }
21901 if (!$this->table_rotate && $level == 1) {
21902 $this->DivLn($adv);
21903 } else {
21904 $this->y += $adv;
21905 }
21906 }
21907
21908 if ($level == 1) {
21909 $this->x = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'];
21910 $x0 = $this->x;
21911 $y0 = $this->y;
21912 $right = $x0 + $this->blk[$this->blklvl]['inner_width'];
21913 $outerfilled = $this->y; // Keep track of how far down the outer DIV bgcolor is painted (NB rowspans)
21914 $this->outerfilled = $this->y;
21915 $this->colsums = [];
21916 } else {
21917 $x0 = $this->x;
21918 $y0 = $this->y;
21919 $right = $x0 + $table['w'];
21920 }
21921
21922 if ($this->table_rotate) {
21923 $temppgwidth = $this->tbrot_maxw;
21924 $this->PageBreakTrigger = $pagetrigger = $y0 + ($this->blk[$this->blklvl]['inner_width']);
21925 if ($level == 1) {
21926 $this->tbrot_y0 = $this->y - $adv - $table['margin']['T'];
21927 $this->tbrot_x0 = $this->x;
21928 $this->tbrot_w = $table['w'];
21929 if ($table['borders_separate']) {
21930 $this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
21931 } else {
21932 $this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['max_cell_border_width']['T'];
21933 }
21934 }
21935 } else {
21936 $this->PageBreakTrigger = $pagetrigger = ($this->h - $this->bMargin);
21937 if ($level == 1) {
21938 $temppgwidth = $this->blk[$this->blklvl]['inner_width'];
21939 if (isset($table['a']) and ( $table['w'] < $this->blk[$this->blklvl]['inner_width'])) {
21940 if ($table['a'] == 'C') {
21941 $x0 += ((($right - $x0) - $table['w']) / 2);
21942 } elseif ($table['a'] == 'R') {
21943 $x0 = $right - $table['w'];
21944 }
21945 }
21946 } else {
21947 $temppgwidth = $table['w'];
21948 }
21949 }
21950 if (!isset($table['overflow'])) {
21951 $table['overflow'] = null;
21952 }
21953 if ($table['overflow'] == 'hidden' && $level == 1 && !$this->table_rotate && !$this->ColActive) {
21954 // Bounding rectangle to clip
21955 $this->tableClipPath = sprintf('q %.3F %.3F %.3F %.3F re W n', $x0 * Mpdf::SCALE, $this->h * Mpdf::SCALE, $this->blk[$this->blklvl]['inner_width'] * Mpdf::SCALE, -$this->h * Mpdf::SCALE);
21956 $this->writer->write($this->tableClipPath);
21957 } else {
21958 $this->tableClipPath = '';
21959 }
21960
21961
21962 if ($table['borders_separate']) {
21963 $indent = $table['margin']['L'] + $table['border_details']['L']['w'] + $table['padding']['L'] + $table['border_spacing_H'] / 2;
21964 } else {
21965 $indent = $table['margin']['L'] + $table['max_cell_border_width']['L'] / 2;
21966 }
21967 $x0 += $indent;
21968
21969 $returny = 0;
21970 $lastCol = 0;
21971 $tableheader = [];
21972 $tablefooter = [];
21973 $tableheaderrowheight = 0;
21974 $tablefooterrowheight = 0;
21975 $footery = 0;
21976
21977 // mPD 3.0 Set the Page & Column where table starts
21978 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
21979 $tablestartpage = 'EVEN';
21980 } elseif (($this->mirrorMargins) && (($this->page) % 2 == 1)) { // ODD
21981 $tablestartpage = 'ODD';
21982 } else {
21983 $tablestartpage = '';
21984 }
21985 if ($this->ColActive) {
21986 $tablestartcolumn = $this->CurrCol;
21987 } else {
21988 $tablestartcolumn = '';
21989 }
21990
21991 $y = $h = 0;
21992 for ($i = 0; $i < $numrows; $i++) { // Rows
21993 if (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i] && $level == 1) {
21994 $tablefooterrowheight += $table['hr'][$i];
21995 $tablefooter[$i][0]['trbackground-images'] = $table['trbackground-images'][$i];
21996 $tablefooter[$i][0]['trgradients'] = $table['trgradients'][$i];
21997 $tablefooter[$i][0]['trbgcolor'] = $table['bgcolor'][$i];
21998 for ($j = $startcol; $j < $numcols; $j++) { // Columns
21999 if (isset($cells[$i][$j]) && $cells[$i][$j]) {
22000 $cell = &$cells[$i][$j];
22001 if ($split) {
22002 if ($table['colPg'][$j] != $splitpg) {
22003 continue;
22004 }
22005 list($x, $w) = $this->_splitTableGetWidth($table, $i, $j);
22006 $js = $j - $startcol;
22007 } else {
22008 list($x, $w) = $this->_tableGetWidth($table, $i, $j);
22009 $js = $j;
22010 }
22011
22012 list($y, $h) = $this->_tableGetHeight($table, $i, $j);
22013 $x += $x0;
22014 $y += $y0;
22015 // Get info of tfoot ==>> table footer
22016 $tablefooter[$i][$js]['x'] = $x;
22017 $tablefooter[$i][$js]['y'] = $y;
22018 $tablefooter[$i][$js]['h'] = $h;
22019 $tablefooter[$i][$js]['w'] = $w;
22020 if (isset($cell['textbuffer'])) {
22021 $tablefooter[$i][$js]['textbuffer'] = $cell['textbuffer'];
22022 } else {
22023 $tablefooter[$i][$js]['textbuffer'] = '';
22024 }
22025 $tablefooter[$i][$js]['a'] = $cell['a'];
22026 $tablefooter[$i][$js]['R'] = $cell['R'];
22027 $tablefooter[$i][$js]['va'] = $cell['va'];
22028 $tablefooter[$i][$js]['mih'] = $cell['mih'];
22029 if (isset($cell['gradient'])) {
22030 $tablefooter[$i][$js]['gradient'] = $cell['gradient']; // *BACKGROUNDS*
22031 }
22032 if (isset($cell['background-image'])) {
22033 $tablefooter[$i][$js]['background-image'] = $cell['background-image']; // *BACKGROUNDS*
22034 }
22035
22036 // CELL FILL BGCOLOR
22037 if (!$this->simpleTables) {
22038 if ($this->packTableData) {
22039 $c = $this->_unpackCellBorder($cell['borderbin']);
22040 $tablefooter[$i][$js]['border'] = $c['border'];
22041 $tablefooter[$i][$js]['border_details'] = $c['border_details'];
22042 } else {
22043 $tablefooter[$i][$js]['border'] = $cell['border'];
22044 $tablefooter[$i][$js]['border_details'] = $cell['border_details'];
22045 }
22046 } elseif ($this->simpleTables) {
22047 $tablefooter[$i][$js]['border'] = $table['simple']['border'];
22048 $tablefooter[$i][$js]['border_details'] = $table['simple']['border_details'];
22049 }
22050 $tablefooter[$i][$js]['bgcolor'] = $cell['bgcolor'];
22051 $tablefooter[$i][$js]['padding'] = $cell['padding'];
22052 if (isset($cell['rowspan'])) {
22053 $tablefooter[$i][$js]['rowspan'] = $cell['rowspan'];
22054 }
22055 if (isset($cell['colspan'])) {
22056 $tablefooter[$i][$js]['colspan'] = $cell['colspan'];
22057 }
22058 if (isset($cell['direction'])) {
22059 $tablefooter[$i][$js]['direction'] = $cell['direction'];
22060 }
22061 if (isset($cell['cellLineHeight'])) {
22062 $tablefooter[$i][$js]['cellLineHeight'] = $cell['cellLineHeight'];
22063 }
22064 if (isset($cell['cellLineStackingStrategy'])) {
22065 $tablefooter[$i][$js]['cellLineStackingStrategy'] = $cell['cellLineStackingStrategy'];
22066 }
22067 if (isset($cell['cellLineStackingShift'])) {
22068 $tablefooter[$i][$js]['cellLineStackingShift'] = $cell['cellLineStackingShift'];
22069 }
22070 }
22071 }
22072 }
22073 }
22074
22075 if ($level == 1) {
22076 $this->writer->write('___TABLE___BACKGROUNDS' . $this->uniqstr);
22077 }
22078 $tableheaderadj = 0;
22079 $tablefooteradj = 0;
22080
22081 $tablestartpageno = $this->page;
22082
22083 // Draw Table Contents and Borders
22084 for ($i = 0; $i < $numrows; $i++) { // Rows
22085 if ($split && $startrow > 0) {
22086 $thnr = (isset($table['is_thead']) ? count($table['is_thead']) : 0);
22087 if ($i >= $thnr && $i < $startrow) {
22088 continue;
22089 }
22090 if ($i == $startrow) {
22091 $returny = $rety - $tableheaderrowheight;
22092 }
22093 }
22094
22095 // Get Maximum row/cell height in row - including rowspan>1 + 1 overlapping
22096 $maxrowheight = $this->_tableGetMaxRowHeight($table, $i);
22097
22098 $skippage = false;
22099 $newpagestarted = false;
22100 for ($j = $startcol; $j < $numcols; $j++) { // Columns
22101 if ($split) {
22102 if ($table['colPg'][$j] > $splitpg) {
22103 break;
22104 }
22105 $lastCol = $j;
22106 }
22107 if (isset($cells[$i][$j]) && $cells[$i][$j]) {
22108 $cell = &$cells[$i][$j];
22109 if ($split) {
22110 $lastCol = $j + (isset($cell['colspan']) ? ($cell['colspan'] - 1) : 0);
22111 list($x, $w) = $this->_splitTableGetWidth($table, $i, $j);
22112 } else {
22113 list($x, $w) = $this->_tableGetWidth($table, $i, $j);
22114 }
22115
22116 list($y, $h) = $this->_tableGetHeight($table, $i, $j);
22117 $x += $x0;
22118 $y += $y0;
22119 $y -= $returny;
22120
22121 if ($table['borders_separate']) {
22122 if (!empty($tablefooter) || $i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows) || (!isset($cell['rowspan']) && ($i + 1) == $numrows)) {
22123 $extra = $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
22124 // $extra = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V']/2;
22125 } else {
22126 $extra = $table['border_spacing_V'] / 2;
22127 }
22128 } else {
22129 $extra = $table['max_cell_border_width']['B'] / 2;
22130 }
22131
22132 if ($j == $startcol && ((($y + $maxrowheight + $extra ) > ($pagetrigger + 0.001)) || (($this->keepColumns || !$this->ColActive) && !empty($tablefooter) && ($y + $maxrowheight + $tablefooterrowheight + $extra) > $pagetrigger) && ($this->tableLevel == 1 && $i < ($numrows - $table['headernrows']))) && ($y0 > 0 || $x0 > 0) && !$this->InFooter && $this->autoPageBreak) {
22133 if (!$skippage) {
22134 $finalSpread = true;
22135 $firstSpread = true;
22136 if ($split) {
22137 for ($t = $startcol; $t < $numcols; $t++) {
22138 // Are there more columns to print on a next page?
22139 if ($table['colPg'][$t] > $splitpg) {
22140 $finalSpread = false;
22141 break;
22142 }
22143 }
22144 if ($startcol > 0) {
22145 $firstSpread = false;
22146 }
22147 }
22148
22149 if (($this->keepColumns || !$this->ColActive) && !empty($tablefooter) && $i > 0) {
22150 $this->y = $y;
22151 $ya = $this->y;
22152 $this->TableHeaderFooter($tablefooter, $tablestartpage, $tablestartcolumn, 'F', $level, $firstSpread, $finalSpread);
22153 if ($this->table_rotate) {
22154 $this->tbrot_h += $this->y - $ya;
22155 }
22156 $tablefooteradj = $this->y - $ya;
22157 }
22158 $y -= $y0;
22159 $returny += $y;
22160
22161 $oldcolumn = $this->CurrCol;
22162 if ($this->AcceptPageBreak()) {
22163 $newpagestarted = true;
22164 $this->y = $y + $y0;
22165
22166 // Move down to account for border-spacing or
22167 // extra half border width in case page breaks in middle
22168 if ($i > 0 && !$this->table_rotate && $level == 1 && !$this->ColActive) {
22169 if ($table['borders_separate']) {
22170 $adv = $table['border_spacing_V'] / 2;
22171 // If table footer
22172 if (($this->keepColumns || !$this->ColActive) && !empty($tablefooter) && $i > 0) {
22173 $adv += ($table['padding']['B'] + $table['border_details']['B']['w']);
22174 }
22175 } else {
22176 $maxbwtop = 0;
22177 $maxbwbottom = 0;
22178 if (!$this->simpleTables) {
22179 if (!empty($tablefooter)) {
22180 $maxbwbottom = $table['max_cell_border_width']['B'];
22181 } else {
22182 $brow = $i - 1;
22183 for ($ctj = 0; $ctj < $numcols; $ctj++) {
22184 if (isset($cells[$brow][$ctj]) && $cells[$brow][$ctj]) {
22185 if ($this->packTableData) {
22186 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$brow][$ctj]['borderbin']);
22187 } else {
22188 $bb = $cells[$brow][$ctj]['border_details']['B']['w'];
22189 }
22190 $maxbwbottom = max($maxbwbottom, $bb);
22191 }
22192 }
22193 }
22194 if (!empty($tableheader)) {
22195 $maxbwtop = $table['max_cell_border_width']['T'];
22196 } else {
22197 $trow = $i - 1;
22198 for ($ctj = 0; $ctj < $numcols; $ctj++) {
22199 if (isset($cells[$trow][$ctj]) && $cells[$trow][$ctj]) {
22200 if ($this->packTableData) {
22201 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$trow][$ctj]['borderbin']);
22202 } else {
22203 $bt = $cells[$trow][$ctj]['border_details']['T']['w'];
22204 }
22205 $maxbwtop = max($maxbwtop, $bt);
22206 }
22207 }
22208 }
22209 } elseif ($this->simpleTables) {
22210 $maxbwtop = $table['simple']['border_details']['T']['w'];
22211 $maxbwbottom = $table['simple']['border_details']['B']['w'];
22212 }
22213 $adv = $maxbwbottom / 2;
22214 }
22215 $this->y += $adv;
22216 }
22217
22218 // Rotated table split over pages - needs this->y for borders/backgrounds
22219 if ($i > 0 && $this->table_rotate && $level == 1) {
22220 // $this->y = $y0 + $this->tbrot_w;
22221 }
22222
22223 if ($this->tableClipPath) {
22224 $this->writer->write("Q");
22225 }
22226
22227 $bx = $x0;
22228 $by = $y0;
22229
22230 if ($table['borders_separate']) {
22231 $bx -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'] / 2);
22232 if ($tablestartpageno != $this->page) { // IF already broken across a previous pagebreak
22233 $by += $table['max_cell_border_width']['T'] / 2;
22234 if (empty($tableheader)) {
22235 $by -= ($table['border_spacing_V'] / 2);
22236 }
22237 } else {
22238 $by -= ($table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2);
22239 }
22240 } elseif ($tablestartpageno != $this->page && !empty($tableheader)) {
22241 $by += $maxbwtop / 2;
22242 }
22243
22244 $by -= $tableheaderadj;
22245 $bh = $this->y - $by + $tablefooteradj;
22246 if (!$table['borders_separate']) {
22247 $bh -= $adv;
22248 }
22249 if ($split) {
22250 $bw = 0;
22251 for ($t = $startcol; $t < $numcols; $t++) {
22252 if ($table['colPg'][$t] == $splitpg) {
22253 $bw += $table['wc'][$t];
22254 }
22255 if ($table['colPg'][$t] > $splitpg) {
22256 break;
22257 }
22258 }
22259 if ($table['borders_separate']) {
22260 if ($firstSpread) {
22261 $bw += $table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'];
22262 } else {
22263 $bx += ($table['padding']['L'] + $table['border_details']['L']['w']);
22264 $bw += $table['border_spacing_H'];
22265 }
22266 if ($finalSpread) {
22267 $bw += $table['padding']['R'] + $table['border_details']['R']['w'] / 2 + $table['border_spacing_H'];
22268 }
22269 }
22270 } else {
22271 $bw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
22272 }
22273
22274 if ($this->splitTableBorderWidth && ($this->keepColumns || !$this->ColActive) && empty($tablefooter) && $i > 0 && $table['border_details']['B']['w']) {
22275 $prevDrawColor = $this->DrawColor;
22276 $lw = $this->LineWidth;
22277 $this->SetLineWidth($this->splitTableBorderWidth);
22278 $this->SetDColor($table['border_details']['B']['c']);
22279 $this->SetLineJoin(0);
22280 $this->SetLineCap(0);
22281 $blx = $bx;
22282 $blw = $bw;
22283 if (!$table['borders_separate']) {
22284 $blx -= ($table['max_cell_border_width']['L'] / 2);
22285 $blw += ($table['max_cell_border_width']['L'] / 2 + $table['max_cell_border_width']['R'] / 2);
22286 }
22287 $this->Line($blx, $this->y + ($this->splitTableBorderWidth / 2), $blx + $blw, $this->y + ($this->splitTableBorderWidth / 2));
22288 $this->DrawColor = $prevDrawColor;
22289 $this->writer->write($this->DrawColor);
22290 $this->SetLineWidth($lw);
22291 $this->SetLineJoin(2);
22292 $this->SetLineCap(2);
22293 }
22294
22295 if (!$this->ColActive && ($i > 0 || $j > 0)) {
22296 if (isset($table['bgcolor'][-1])) {
22297 $color = $this->colorConverter->convert($table['bgcolor'][-1], $this->PDFAXwarnings);
22298 if ($color) {
22299 if (!$table['borders_separate']) {
22300 $bh -= $table['max_cell_border_width']['B'] / 2;
22301 }
22302 $this->tableBackgrounds[$level * 9][] = ['gradient' => false, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'col' => $color];
22303 }
22304 }
22305
22306 /* -- BACKGROUNDS -- */
22307 if (isset($table['gradient'])) {
22308 $g = $this->gradient->parseBackgroundGradient($table['gradient']);
22309 if ($g) {
22310 $this->tableBackgrounds[$level * 9 + 1][] = ['gradient' => true, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
22311 }
22312 }
22313
22314 if (isset($table['background-image'])) {
22315 if ($table['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['background-image']['gradient'])) {
22316 $g = $this->gradient->parseMozGradient($table['background-image']['gradient']);
22317 if ($g) {
22318 $this->tableBackgrounds[$level * 9 + 1][] = ['gradient' => true, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
22319 }
22320 } else {
22321 $image_id = $table['background-image']['image_id'];
22322 $orig_w = $table['background-image']['orig_w'];
22323 $orig_h = $table['background-image']['orig_h'];
22324 $x_pos = $table['background-image']['x_pos'];
22325 $y_pos = $table['background-image']['y_pos'];
22326 $x_repeat = $table['background-image']['x_repeat'];
22327 $y_repeat = $table['background-image']['y_repeat'];
22328 $resize = $table['background-image']['resize'];
22329 $opacity = $table['background-image']['opacity'];
22330 $itype = $table['background-image']['itype'];
22331 $this->tableBackgrounds[$level * 9 + 2][] = ['x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => '', 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
22332 }
22333 }
22334 /* -- END BACKGROUNDS -- */
22335 }
22336
22337 // $this->AcceptPageBreak() has moved tablebuffer to $this->pages content
22338 if ($this->tableBackgrounds) {
22339 $s = $this->PrintTableBackgrounds();
22340 if ($this->bufferoutput) {
22341 $this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->headerbuffer);
22342 $this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->headerbuffer);
22343 } else {
22344 $this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
22345 $this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->pages[$this->page]);
22346 }
22347 $this->tableBackgrounds = [];
22348 }
22349
22350 if ($split) {
22351 if ($i == 0 && $j == 0) {
22352 $y0 = -1;
22353 } elseif ($finalSpread) {
22354 $splitpg = 0;
22355 $startcol = 0;
22356 $startrow = $i;
22357 } else {
22358 $splitpg++;
22359 $startcol = $t;
22360 $returny -= $y;
22361 }
22362 return [false, $startrow, $startcol, $splitpg, $returny, $y0];
22363 }
22364
22365 $this->AddPage($this->CurOrientation);
22366
22367 $this->writer->write('___TABLE___BACKGROUNDS' . $this->uniqstr);
22368
22369
22370 if ($this->tableClipPath) {
22371 $this->writer->write($this->tableClipPath);
22372 }
22373
22374 // Added to correct for OddEven Margins
22375 $x = $x + $this->MarginCorrection;
22376 $x0 = $x0 + $this->MarginCorrection;
22377
22378 if ($this->splitTableBorderWidth && ($this->keepColumns || !$this->ColActive) && empty($tableheader) && $i > 0 && $table['border_details']['T']['w']) {
22379 $prevDrawColor = $this->DrawColor;
22380 $lw = $this->LineWidth;
22381 $this->SetLineWidth($this->splitTableBorderWidth);
22382 $this->SetDColor($table['border_details']['T']['c']);
22383 $this->SetLineJoin(0);
22384 $this->SetLineCap(0);
22385 $blx += $this->MarginCorrection;
22386 $this->Line($blx, $this->y - ($this->splitTableBorderWidth / 2), $blx + $blw, $this->y - ($this->splitTableBorderWidth / 2));
22387 $this->DrawColor = $prevDrawColor;
22388 $this->writer->write($this->DrawColor);
22389 $this->SetLineWidth($lw);
22390 $this->SetLineJoin(2);
22391 $this->SetLineCap(2);
22392 }
22393
22394 // Move down to account for half of top border-spacing or
22395 // extra half border width in case page was broken in middle
22396 if ($i > 0 && !$this->table_rotate && $level == 1 && $table['headernrows'] == 0) {
22397 if ($table['borders_separate']) {
22398 $adv = $table['border_spacing_V'] / 2;
22399 } else {
22400 $maxbwtop = 0;
22401 for ($ctj = 0; $ctj < $numcols; $ctj++) {
22402 if (isset($cells[$i][$ctj]) && $cells[$i][$ctj]) {
22403 if (!$this->simpleTables) {
22404 if ($this->packTableData) {
22405 list($bt, $br, $bb, $bl) = $this->_getBorderWidths($cells[$i][$ctj]['borderbin']);
22406 } else {
22407 $bt = $cells[$i][$ctj]['border_details']['T']['w'];
22408 }
22409 $maxbwtop = max($maxbwtop, $bt);
22410 } elseif ($this->simpleTables) {
22411 $maxbwtop = max($maxbwtop, $table['simple']['border_details']['T']['w']);
22412 }
22413 }
22414 }
22415 $adv = $maxbwtop / 2;
22416 }
22417 $this->y += $adv;
22418 }
22419
22420
22421 if ($this->table_rotate) {
22422 $this->tbrot_x0 = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['padding_left'] + $this->blk[$this->blklvl]['border_left']['w'];
22423 if ($table['borders_separate']) {
22424 $this->tbrot_h = $table['margin']['T'] + $table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2;
22425 } else {
22426 $this->tbrot_h = $table['margin']['T'] + $table['max_cell_border_width']['T'];
22427 }
22428 $this->tbrot_y0 = $this->y;
22429 $pagetrigger = $y0 - $tableheaderadj + ($this->blk[$this->blklvl]['inner_width']);
22430 } else {
22431 $pagetrigger = $this->PageBreakTrigger;
22432 }
22433
22434 if ($this->kwt_saved && $level == 1) {
22435 $this->kwt_moved = true;
22436 }
22437
22438
22439 if (!empty($tableheader)) {
22440 $ya = $this->y;
22441 $this->TableHeaderFooter($tableheader, $tablestartpage, $tablestartcolumn, 'H', $level);
22442 if ($this->table_rotate) {
22443 $this->tbrot_h = $this->y - $ya;
22444 }
22445 $tableheaderadj = $this->y - $ya;
22446 } elseif ($i == 0 && !$this->table_rotate && $level == 1 && !$this->ColActive) {
22447 // Advance down page
22448 if ($table['borders_separate']) {
22449 $adv = $table['border_spacing_V'] / 2 + $table['border_details']['T']['w'] + $table['padding']['T'];
22450 } else {
22451 $adv = $table['max_cell_border_width']['T'] / 2;
22452 }
22453 if ($adv) {
22454 if ($this->table_rotate) {
22455 $this->y += ($adv);
22456 } else {
22457 $this->DivLn($adv, $this->blklvl, true);
22458 }
22459 }
22460 }
22461
22462 $outerfilled = 0;
22463 $y = $y0 = $this->y;
22464 }
22465
22466 /* -- COLUMNS -- */
22467 // COLS
22468 // COLUMN CHANGE
22469 if ($this->CurrCol != $oldcolumn) {
22470 // Added to correct for Columns
22471 $x += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
22472 $x0 += $this->ChangeColumn * ($this->ColWidth + $this->ColGap);
22473 if ($this->CurrCol == 0) { // just added a page - possibly with tableheader
22474 $y0 = $this->y; // this->y0 is global used by Columns - $y0 is internal to tablewrite
22475 } else {
22476 $y0 = $this->y0; // this->y0 is global used by Columns - $y0 is internal to tablewrite
22477 }
22478 $y = $y0;
22479 $outerfilled = 0;
22480 if ($this->CurrCol != 0 && ($this->keepColumns && $this->ColActive) && !empty($tableheader) && $i > 0) {
22481 $this->x = $x;
22482 $this->y = $y;
22483 $this->TableHeaderFooter($tableheader, $tablestartpage, $tablestartcolumn, 'H', $level);
22484 $y0 = $y = $this->y;
22485 }
22486 }
22487 /* -- END COLUMNS -- */
22488 }
22489 $skippage = true;
22490 }
22491
22492 $this->x = $x;
22493 $this->y = $y;
22494
22495 if ($this->kwt_saved && $level == 1) {
22496 $this->printkwtbuffer();
22497 $x0 = $x = $this->x;
22498 $y0 = $y = $this->y;
22499 $this->kwt_moved = false;
22500 $this->kwt_saved = false;
22501 }
22502
22503
22504 // Set the Page & Column where table actually starts
22505 if ($i == 0 && $j == 0 && $level == 1) {
22506 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
22507 $tablestartpage = 'EVEN';
22508 } elseif (($this->mirrorMargins) && (($this->page) % 2 == 1)) { // ODD
22509 $tablestartpage = 'ODD';
22510 } else {
22511 $tablestartpage = '';
22512 }
22513 $tablestartpageno = $this->page;
22514 if ($this->ColActive) {
22515 $tablestartcolumn = $this->CurrCol;
22516 } // *COLUMNS*
22517 }
22518
22519 // ALIGN
22520 $align = $cell['a'];
22521
22522 /* -- COLUMNS -- */
22523 // If outside columns, this is done in PaintDivBB
22524 if ($this->ColActive) {
22525 // OUTER FILL BGCOLOR of DIVS
22526 if ($this->blklvl > 0 && ($j == 0) && !$this->table_rotate && $level == 1) {
22527 $firstblockfill = $this->GetFirstBlockFill();
22528 if ($firstblockfill && $this->blklvl >= $firstblockfill) {
22529 $divh = $maxrowheight;
22530 // Last row
22531 if ((!isset($cell['rowspan']) && $i == $numrows - 1) || (isset($cell['rowspan']) && (($i == $numrows - 1 && $cell['rowspan'] < 2) || ($cell['rowspan'] > 1 && ($i + $cell['rowspan'] - 1) == $numrows - 1)))) {
22532 if ($table['borders_separate']) {
22533 $adv = $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
22534 } else {
22535 $adv = $table['margin']['B'] + $table['max_cell_border_width']['B'] / 2;
22536 }
22537 $divh += $adv; // last row: fill bottom half of bottom border (y advanced at end)
22538 }
22539
22540 if (($this->y + $divh) > $outerfilled) { // if not already painted by previous rowspan
22541 $bak_x = $this->x;
22542 $bak_y = $this->y;
22543 if ($outerfilled > $this->y) {
22544 $divh = ($this->y + $divh) - $outerfilled;
22545 $this->y = $outerfilled;
22546 }
22547
22548 $this->DivLn($divh, -3, false);
22549 $outerfilled = $this->y + $divh;
22550 // Reset current block fill
22551 $bcor = $this->blk[$this->blklvl]['bgcolorarray'];
22552 if ($bcor) {
22553 $this->SetFColor($bcor);
22554 }
22555 $this->x = $bak_x;
22556 $this->y = $bak_y;
22557 }
22558 }
22559 }
22560 }
22561
22562 // TABLE BACKGROUND FILL BGCOLOR - for cellSpacing
22563 if ($this->ColActive) {
22564 if ($table['borders_separate']) {
22565 $fill = isset($table['bgcolor'][-1]) ? $table['bgcolor'][-1] : 0;
22566 if ($fill) {
22567 $color = $this->colorConverter->convert($fill, $this->PDFAXwarnings);
22568 if ($color) {
22569 $xadj = ($table['border_spacing_H'] / 2);
22570 $yadj = ($table['border_spacing_V'] / 2);
22571 $wadj = $table['border_spacing_H'];
22572 $hadj = $table['border_spacing_V'];
22573 if ($i == 0) { // Top
22574 $yadj += $table['padding']['T'] + $table['border_details']['T']['w'];
22575 $hadj += $table['padding']['T'] + $table['border_details']['T']['w'];
22576 }
22577 if ($j == 0) { // Left
22578 $xadj += $table['padding']['L'] + $table['border_details']['L']['w'];
22579 $wadj += $table['padding']['L'] + $table['border_details']['L']['w'];
22580 }
22581 if ($i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows) || (!isset($cell['rowspan']) && ($i + 1) == $numrows)) { // Bottom
22582 $hadj += $table['padding']['B'] + $table['border_details']['B']['w'];
22583 }
22584 if ($j == ($numcols - 1) || (isset($cell['colspan']) && ($j + $cell['colspan']) == $numcols) || (!isset($cell['colspan']) && ($j + 1) == $numcols)) { // Right
22585 $wadj += $table['padding']['R'] + $table['border_details']['R']['w'];
22586 }
22587 $this->SetFColor($color);
22588 $this->Rect($x - $xadj, $y - $yadj, $w + $wadj, $h + $hadj, 'F');
22589 }
22590 }
22591 }
22592 }
22593 /* -- END COLUMNS -- */
22594
22595 if ($table['empty_cells'] != 'hide' || !empty($cell['textbuffer']) || (isset($cell['nestedcontent']) && $cell['nestedcontent']) || !$table['borders_separate']) {
22596 $paintcell = true;
22597 } else {
22598 $paintcell = false;
22599 }
22600
22601 // Set Borders
22602 $bord = 0;
22603 $bord_det = [];
22604
22605 if (!$this->simpleTables) {
22606 if ($this->packTableData) {
22607 $c = $this->_unpackCellBorder($cell['borderbin']);
22608 $bord = $c['border'];
22609 $bord_det = $c['border_details'];
22610 } else {
22611 $bord = $cell['border'];
22612 $bord_det = $cell['border_details'];
22613 }
22614 } elseif ($this->simpleTables) {
22615 $bord = $table['simple']['border'];
22616 $bord_det = $table['simple']['border_details'];
22617 }
22618
22619 // TABLE ROW OR CELL FILL BGCOLOR
22620 $fill = 0;
22621 if (isset($cell['bgcolor']) && $cell['bgcolor'] && $cell['bgcolor'] != 'transparent') {
22622 $fill = $cell['bgcolor'];
22623 $leveladj = 6;
22624 } elseif (isset($table['bgcolor'][$i]) && $table['bgcolor'][$i] && $table['bgcolor'][$i] != 'transparent') { // Row color
22625 $fill = $table['bgcolor'][$i];
22626 $leveladj = 3;
22627 }
22628 if ($fill && $paintcell) {
22629 $color = $this->colorConverter->convert($fill, $this->PDFAXwarnings);
22630 if ($color) {
22631 if ($table['borders_separate']) {
22632 if ($this->ColActive) {
22633 $this->SetFColor($color);
22634 $this->Rect($x + ($table['border_spacing_H'] / 2), $y + ($table['border_spacing_V'] / 2), $w - $table['border_spacing_H'], $h - $table['border_spacing_V'], 'F');
22635 } else {
22636 $this->tableBackgrounds[$level * 9 + $leveladj][] = ['gradient' => false, 'x' => ($x + ($table['border_spacing_H'] / 2)), 'y' => ($y + ($table['border_spacing_V'] / 2)), 'w' => ($w - $table['border_spacing_H']), 'h' => ($h - $table['border_spacing_V']), 'col' => $color];
22637 }
22638 } else {
22639 if ($this->ColActive) {
22640 $this->SetFColor($color);
22641 $this->Rect($x, $y, $w, $h, 'F');
22642 } else {
22643 $this->tableBackgrounds[$level * 9 + $leveladj][] = ['gradient' => false, 'x' => $x, 'y' => $y, 'w' => $w, 'h' => $h, 'col' => $color];
22644 }
22645 }
22646 }
22647 }
22648
22649 /* -- BACKGROUNDS -- */
22650 if (isset($cell['gradient']) && $cell['gradient'] && $paintcell) {
22651 $g = $this->gradient->parseBackgroundGradient($cell['gradient']);
22652 if ($g) {
22653 if ($table['borders_separate']) {
22654 $px = $x + ($table['border_spacing_H'] / 2);
22655 $py = $y + ($table['border_spacing_V'] / 2);
22656 $pw = $w - $table['border_spacing_H'];
22657 $ph = $h - $table['border_spacing_V'];
22658 } else {
22659 $px = $x;
22660 $py = $y;
22661 $pw = $w;
22662 $ph = $h;
22663 }
22664 if ($this->ColActive) {
22665 $this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
22666 } else {
22667 $this->tableBackgrounds[$level * 9 + 7][] = ['gradient' => true, 'x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
22668 }
22669 }
22670 }
22671
22672 if (isset($cell['background-image']) && $paintcell) {
22673 if (isset($cell['background-image']['gradient']) && $cell['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $cell['background-image']['gradient'])) {
22674 $g = $this->gradient->parseMozGradient($cell['background-image']['gradient']);
22675 if ($g) {
22676 if ($table['borders_separate']) {
22677 $px = $x + ($table['border_spacing_H'] / 2);
22678 $py = $y + ($table['border_spacing_V'] / 2);
22679 $pw = $w - $table['border_spacing_H'];
22680 $ph = $h - $table['border_spacing_V'];
22681 } else {
22682 $px = $x;
22683 $py = $y;
22684 $pw = $w;
22685 $ph = $h;
22686 }
22687 if ($this->ColActive) {
22688 $this->gradient->Gradient($px, $py, $pw, $ph, $g['type'], $g['stops'], $g['colorspace'], $g['coords'], $g['extend']);
22689 } else {
22690 $this->tableBackgrounds[$level * 9 + 7][] = ['gradient' => true, 'x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
22691 }
22692 }
22693 } elseif (isset($cell['background-image']['image_id']) && $cell['background-image']['image_id']) { // Background pattern
22694 $n = count($this->patterns) + 1;
22695 if ($table['borders_separate']) {
22696 $px = $x + ($table['border_spacing_H'] / 2);
22697 $py = $y + ($table['border_spacing_V'] / 2);
22698 $pw = $w - $table['border_spacing_H'];
22699 $ph = $h - $table['border_spacing_V'];
22700 } else {
22701 $px = $x;
22702 $py = $y;
22703 $pw = $w;
22704 $ph = $h;
22705 }
22706 if ($this->ColActive) {
22707 list($orig_w, $orig_h, $x_repeat, $y_repeat) = $this->_resizeBackgroundImage($cell['background-image']['orig_w'], $cell['background-image']['orig_h'], $pw, $ph, $cell['background-image']['resize'], $cell['background-image']['x_repeat'], $cell['background-image']['y_repeat']);
22708 $this->patterns[$n] = ['x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'pgh' => $this->h, 'image_id' => $cell['background-image']['image_id'], 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $cell['background-image']['x_pos'], 'y_pos' => $cell['background-image']['y_pos'], 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat];
22709 if ($cell['background-image']['opacity'] > 0 && $cell['background-image']['opacity'] < 1) {
22710 $opac = $this->SetAlpha($cell['background-image']['opacity'], 'Normal', true);
22711 } else {
22712 $opac = '';
22713 }
22714 $this->writer->write(sprintf('q /Pattern cs /P%d scn %s %.3F %.3F %.3F %.3F re f Q', $n, $opac, $px * Mpdf::SCALE, ($this->h - $py) * Mpdf::SCALE, $pw * Mpdf::SCALE, -$ph * Mpdf::SCALE));
22715 } else {
22716 $image_id = $cell['background-image']['image_id'];
22717 $orig_w = $cell['background-image']['orig_w'];
22718 $orig_h = $cell['background-image']['orig_h'];
22719 $x_pos = $cell['background-image']['x_pos'];
22720 $y_pos = $cell['background-image']['y_pos'];
22721 $x_repeat = $cell['background-image']['x_repeat'];
22722 $y_repeat = $cell['background-image']['y_repeat'];
22723 $resize = $cell['background-image']['resize'];
22724 $opacity = $cell['background-image']['opacity'];
22725 $itype = $cell['background-image']['itype'];
22726 $this->tableBackgrounds[$level * 9 + 8][] = ['x' => $px, 'y' => $py, 'w' => $pw, 'h' => $ph, 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => '', 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
22727 }
22728 }
22729 }
22730 /* -- END BACKGROUNDS -- */
22731
22732 if (isset($cell['colspan']) && $cell['colspan'] > 1) {
22733 $ccolsp = $cell['colspan'];
22734 } else {
22735 $ccolsp = 1;
22736 }
22737 if (isset($cell['rowspan']) && $cell['rowspan'] > 1) {
22738 $crowsp = $cell['rowspan'];
22739 } else {
22740 $crowsp = 1;
22741 }
22742
22743
22744 // but still need to do this for repeated headers...
22745 if (!$table['borders_separate'] && $this->tabletheadjustfinished && !$this->simpleTables) {
22746 if (isset($table['topntail']) && $table['topntail']) {
22747 $bord_det['T'] = $this->border_details($table['topntail']);
22748 $bord_det['T']['w'] /= $this->shrin_k;
22749 $this->setBorder($bord, Border::TOP);
22750 }
22751 if (isset($table['thead-underline']) && $table['thead-underline']) {
22752 $bord_det['T'] = $this->border_details($table['thead-underline']);
22753 $bord_det['T']['w'] /= $this->shrin_k;
22754 $this->setBorder($bord, Border::TOP);
22755 }
22756 }
22757
22758
22759 // Get info of first row ==>> table header
22760 // Use > 1 row if THEAD
22761 if (isset($table['is_thead'][$i]) && $table['is_thead'][$i] && $level == 1) {
22762 if ($j == 0) {
22763 $tableheaderrowheight += $table['hr'][$i];
22764 }
22765 $tableheader[$i][0]['trbackground-images'] = (isset($table['trbackground-images'][$i]) ? $table['trbackground-images'][$i] : null);
22766 $tableheader[$i][0]['trgradients'] = (isset($table['trgradients'][$i]) ? $table['trgradients'][$i] : null);
22767 $tableheader[$i][0]['trbgcolor'] = (isset($table['bgcolor'][$i]) ? $table['bgcolor'][$i] : null);
22768 $tableheader[$i][$j]['x'] = $x;
22769 $tableheader[$i][$j]['y'] = $y;
22770 $tableheader[$i][$j]['h'] = $h;
22771 $tableheader[$i][$j]['w'] = $w;
22772 if (isset($cell['textbuffer'])) {
22773 $tableheader[$i][$j]['textbuffer'] = $cell['textbuffer'];
22774 } else {
22775 $tableheader[$i][$j]['textbuffer'] = '';
22776 }
22777 $tableheader[$i][$j]['a'] = $cell['a'];
22778 $tableheader[$i][$j]['R'] = $cell['R'];
22779
22780 $tableheader[$i][$j]['va'] = $cell['va'];
22781 $tableheader[$i][$j]['mih'] = $cell['mih'];
22782 $tableheader[$i][$j]['gradient'] = (isset($cell['gradient']) ? $cell['gradient'] : null); // *BACKGROUNDS*
22783 $tableheader[$i][$j]['background-image'] = (isset($cell['background-image']) ? $cell['background-image'] : null); // *BACKGROUNDS*
22784 $tableheader[$i][$j]['rowspan'] = (isset($cell['rowspan']) ? $cell['rowspan'] : null);
22785 $tableheader[$i][$j]['colspan'] = (isset($cell['colspan']) ? $cell['colspan'] : null);
22786 $tableheader[$i][$j]['bgcolor'] = $cell['bgcolor'];
22787
22788 if (!$this->simpleTables) {
22789 $tableheader[$i][$j]['border'] = $bord;
22790 $tableheader[$i][$j]['border_details'] = $bord_det;
22791 } elseif ($this->simpleTables) {
22792 $tableheader[$i][$j]['border'] = $table['simple']['border'];
22793 $tableheader[$i][$j]['border_details'] = $table['simple']['border_details'];
22794 }
22795 $tableheader[$i][$j]['padding'] = $cell['padding'];
22796 if (isset($cell['direction'])) {
22797 $tableheader[$i][$j]['direction'] = $cell['direction'];
22798 }
22799 if (isset($cell['cellLineHeight'])) {
22800 $tableheader[$i][$j]['cellLineHeight'] = $cell['cellLineHeight'];
22801 }
22802 if (isset($cell['cellLineStackingStrategy'])) {
22803 $tableheader[$i][$j]['cellLineStackingStrategy'] = $cell['cellLineStackingStrategy'];
22804 }
22805 if (isset($cell['cellLineStackingShift'])) {
22806 $tableheader[$i][$j]['cellLineStackingShift'] = $cell['cellLineStackingShift'];
22807 }
22808 }
22809
22810 // CELL BORDER
22811 if ($bord) {
22812 if ($table['borders_separate'] && $paintcell) {
22813 $this->_tableRect($x + ($table['border_spacing_H'] / 2) + ($bord_det['L']['w'] / 2), $y + ($table['border_spacing_V'] / 2) + ($bord_det['T']['w'] / 2), $w - $table['border_spacing_H'] - ($bord_det['L']['w'] / 2) - ($bord_det['R']['w'] / 2), $h - $table['border_spacing_V'] - ($bord_det['T']['w'] / 2) - ($bord_det['B']['w'] / 2), $bord, $bord_det, false, $table['borders_separate']);
22814 } elseif (!$table['borders_separate']) {
22815 $this->_tableRect($x, $y, $w, $h, $bord, $bord_det, true, $table['borders_separate']); // true causes buffer
22816 }
22817 }
22818
22819 // VERTICAL ALIGN
22820 if ($cell['R'] && intval($cell['R']) > 0 && intval($cell['R']) < 90 && isset($cell['va']) && $cell['va'] != 'B') {
22821 $cell['va'] = 'B';
22822 }
22823 if (!isset($cell['va']) || $cell['va'] == 'M') {
22824 $this->y += ($h - $cell['mih']) / 2;
22825 } elseif (isset($cell['va']) && $cell['va'] == 'B') {
22826 $this->y += $h - $cell['mih'];
22827 }
22828
22829 // NESTED CONTENT
22830 // TEXT (and nested tables)
22831
22832 $this->divwidth = $w;
22833 if (!empty($cell['textbuffer'])) {
22834 $this->cellTextAlign = $align;
22835 $this->cellLineHeight = $cell['cellLineHeight'];
22836 $this->cellLineStackingStrategy = $cell['cellLineStackingStrategy'];
22837 $this->cellLineStackingShift = $cell['cellLineStackingShift'];
22838 if ($level == 1) {
22839 if (isset($table['is_tfoot'][$i]) && $table['is_tfoot'][$i]) {
22840 if (preg_match('/{colsum([0-9]*)[_]*}/', $cell['textbuffer'][0][0], $m)) {
22841 $rep = sprintf("%01." . intval($m[1]) . "f", $this->colsums[$j]);
22842 $cell['textbuffer'][0][0] = preg_replace('/{colsum[0-9_]*}/', $rep, $cell['textbuffer'][0][0]);
22843 }
22844 } elseif (!isset($table['is_thead'][$i])) {
22845 if (isset($this->colsums[$j])) {
22846 $this->colsums[$j] += $this->toFloat($cell['textbuffer'][0][0]);
22847 } else {
22848 $this->colsums[$j] = $this->toFloat($cell['textbuffer'][0][0]);
22849 }
22850 }
22851 }
22852 $opy = $this->y;
22853 // mPDF ITERATION
22854 if ($this->iterationCounter) {
22855 foreach ($cell['textbuffer'] as $k => $t) {
22856 if (preg_match('/{iteration ([a-zA-Z0-9_]+)}/', $t[0], $m)) {
22857 $vname = '__' . $m[1] . '_';
22858 if (!isset($this->$vname)) {
22859 $this->$vname = 1;
22860 } else {
22861 $this->$vname++;
22862 }
22863 $cell['textbuffer'][$k][0] = preg_replace('/{iteration ' . $m[1] . '}/', $this->$vname, $cell['textbuffer'][$k][0]);
22864 }
22865 }
22866 }
22867
22868
22869 if ($cell['R']) {
22870 $cellPtSize = $cell['textbuffer'][0][11] / $this->shrin_k;
22871 if (!$cellPtSize) {
22872 $cellPtSize = $this->default_font_size;
22873 }
22874 $cellFontHeight = ($cellPtSize / Mpdf::SCALE);
22875 $opx = $this->x;
22876 $angle = intval($cell['R']);
22877 // Only allow 45 to 89 degrees (when bottom-aligned) or exactly 90 or -90
22878 if ($angle > 90) {
22879 $angle = 90;
22880 } elseif ($angle > 0 && $angle < 45) {
22881 $angle = 45;
22882 } elseif ($angle < 0) {
22883 $angle = -90;
22884 }
22885 $offset = ((sin(deg2rad($angle))) * 0.37 * $cellFontHeight);
22886 if (isset($cell['a']) && $cell['a'] == 'R') {
22887 $this->x += ($w) + ($offset) - ($cellFontHeight / 3) - ($cell['padding']['R'] + ($table['border_spacing_H'] / 2));
22888 } elseif (!isset($cell['a']) || $cell['a'] == 'C') {
22889 $this->x += ($w / 2) + ($offset);
22890 } else {
22891 $this->x += ($offset) + ($cellFontHeight / 3) + ($cell['padding']['L'] + ($table['border_spacing_H'] / 2));
22892 }
22893 $str = '';
22894 foreach ($cell['textbuffer'] as $t) {
22895 $str .= $t[0] . ' ';
22896 }
22897 $str = rtrim($str);
22898 if (!isset($cell['va']) || $cell['va'] == 'M') {
22899 $this->y -= ($h - $cell['mih']) / 2; // Undo what was added earlier VERTICAL ALIGN
22900 if ($angle > 0) {
22901 $this->y += (($h - $cell['mih']) / 2) + $cell['padding']['T'] + ($cell['mih'] - ($cell['padding']['T'] + $cell['padding']['B']));
22902 } elseif ($angle < 0) {
22903 $this->y += (($h - $cell['mih']) / 2) + ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
22904 }
22905 } elseif (isset($cell['va']) && $cell['va'] == 'B') {
22906 $this->y -= $h - $cell['mih']; // Undo what was added earlier VERTICAL ALIGN
22907 if ($angle > 0) {
22908 $this->y += $h - ($cell['padding']['B'] + ($table['border_spacing_V'] / 2));
22909 } elseif ($angle < 0) {
22910 $this->y += $h - $cell['mih'] + ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
22911 }
22912 } elseif (isset($cell['va']) && $cell['va'] == 'T') {
22913 if ($angle > 0) {
22914 $this->y += $cell['mih'] - ($cell['padding']['B'] + ($table['border_spacing_V'] / 2));
22915 } elseif ($angle < 0) {
22916 $this->y += ($cell['padding']['T'] + ($table['border_spacing_V'] / 2));
22917 }
22918 }
22919 $this->Rotate($angle, $this->x, $this->y);
22920 $s_fs = $this->FontSizePt;
22921 $s_f = $this->FontFamily;
22922 $s_st = $this->FontStyle;
22923 if (!empty($cell['textbuffer'][0][3])) { // Font Color
22924 $cor = $cell['textbuffer'][0][3];
22925 $this->SetTColor($cor);
22926 }
22927 $this->SetFont($cell['textbuffer'][0][4], $cell['textbuffer'][0][2], $cellPtSize, true, true);
22928
22929 $this->magic_reverse_dir($str, $this->directionality, $cell['textbuffer'][0][18]);
22930 $this->Text($this->x, $this->y, $str, $cell['textbuffer'][0][18], $cell['textbuffer'][0][8]); // textvar
22931 $this->Rotate(0);
22932 $this->SetFont($s_f, $s_st, $s_fs, true, true);
22933 $this->SetTColor(0);
22934 $this->x = $opx;
22935 } else {
22936 if (!$this->simpleTables) {
22937 if ($bord_det) {
22938 $btlw = $bord_det['L']['w'];
22939 $btrw = $bord_det['R']['w'];
22940 $bttw = $bord_det['T']['w'];
22941 } else {
22942 $btlw = 0;
22943 $btrw = 0;
22944 $bttw = 0;
22945 }
22946 if ($table['borders_separate']) {
22947 $xadj = $btlw + $cell['padding']['L'] + ($table['border_spacing_H'] / 2);
22948 $wadj = $btlw + $btrw + $cell['padding']['L'] + $cell['padding']['R'] + $table['border_spacing_H'];
22949 $yadj = $bttw + $cell['padding']['T'] + ($table['border_spacing_H'] / 2);
22950 } else {
22951 $xadj = $btlw / 2 + $cell['padding']['L'];
22952 $wadj = ($btlw + $btrw) / 2 + $cell['padding']['L'] + $cell['padding']['R'];
22953 $yadj = $bttw / 2 + $cell['padding']['T'];
22954 }
22955 } elseif ($this->simpleTables) {
22956 if ($table['borders_separate']) { // NB twice border width
22957 $xadj = $table['simple']['border_details']['L']['w'] + $cell['padding']['L'] + ($table['border_spacing_H'] / 2);
22958 $wadj = $table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w'] + $cell['padding']['L'] + $cell['padding']['R'] + $table['border_spacing_H'];
22959 $yadj = $table['simple']['border_details']['T']['w'] + $cell['padding']['T'] + ($table['border_spacing_H'] / 2);
22960 } else {
22961 $xadj = $table['simple']['border_details']['L']['w'] / 2 + $cell['padding']['L'];
22962 $wadj = ($table['simple']['border_details']['L']['w'] + $table['simple']['border_details']['R']['w']) / 2 + $cell['padding']['L'] + $cell['padding']['R'];
22963 $yadj = $table['simple']['border_details']['T']['w'] / 2 + $cell['padding']['T'];
22964 }
22965 }
22966 $this->decimal_offset = 0;
22967 if (substr($cell['a'], 0, 1) == 'D') {
22968 if (isset($cell['colspan']) && $cell['colspan'] > 1) {
22969 $this->cellTextAlign = $c['a'] = substr($cell['a'], 2, 1);
22970 } else {
22971 $smax = $table['decimal_align'][$j]['maxs0'];
22972 $d_content = $table['decimal_align'][$j]['maxs0'] + $table['decimal_align'][$j]['maxs1'];
22973 $this->decimal_offset = $smax;
22974 $extra = ($w - $d_content - $wadj);
22975 if ($extra > 0) {
22976 if (substr($cell['a'], 2, 1) == 'R') {
22977 $this->decimal_offset += $extra;
22978 } elseif (substr($cell['a'], 2, 1) == 'C') {
22979 $this->decimal_offset += ($extra) / 2;
22980 }
22981 }
22982 }
22983 }
22984 $this->divwidth = $w - $wadj;
22985 if ($this->divwidth == 0) {
22986 $this->divwidth = 0.0001;
22987 }
22988 $this->x += $xadj;
22989 $this->y += $yadj;
22990 $this->printbuffer($cell['textbuffer'], '', true, false, $cell['direction']);
22991 }
22992 $this->y = $opy;
22993 }
22994
22995 /* -- BACKGROUNDS -- */
22996 if (!$this->ColActive) {
22997 if (isset($table['trgradients'][$i]) && ($j == 0 || $table['borders_separate'])) {
22998 $g = $this->gradient->parseBackgroundGradient($table['trgradients'][$i]);
22999 if ($g) {
23000 $gx = $x0;
23001 $gy = $y;
23002 $gh = $h;
23003 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
23004 if ($table['borders_separate']) {
23005 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
23006 $clx = $x + ($table['border_spacing_H'] / 2);
23007 $cly = $y + ($table['border_spacing_V'] / 2);
23008 $clw = $w - $table['border_spacing_H'];
23009 $clh = $h - $table['border_spacing_V'];
23010 // Set clipping path
23011 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
23012 $this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => $s];
23013 } else {
23014 $this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
23015 }
23016 }
23017 }
23018 if (isset($table['trbackground-images'][$i]) && ($j == 0 || $table['borders_separate'])) {
23019 if (isset($table['trbackground-images'][$i]['gradient']) && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['trbackground-images'][$i]['gradient'])) {
23020 $g = $this->gradient->parseMozGradient($table['trbackground-images'][$i]['gradient']);
23021 if ($g) {
23022 $gx = $x0;
23023 $gy = $y;
23024 $gh = $h;
23025 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
23026 if ($table['borders_separate']) {
23027 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
23028 $clx = $x + ($table['border_spacing_H'] / 2);
23029 $cly = $y + ($table['border_spacing_V'] / 2);
23030 $clw = $w - $table['border_spacing_H'];
23031 $clh = $h - $table['border_spacing_V'];
23032 // Set clipping path
23033 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
23034 $this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => $s];
23035 } else {
23036 $this->tableBackgrounds[$level * 9 + 4][] = ['gradient' => true, 'x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
23037 }
23038 }
23039 } else {
23040 $image_id = $table['trbackground-images'][$i]['image_id'];
23041 $orig_w = $table['trbackground-images'][$i]['orig_w'];
23042 $orig_h = $table['trbackground-images'][$i]['orig_h'];
23043 $x_pos = $table['trbackground-images'][$i]['x_pos'];
23044 $y_pos = $table['trbackground-images'][$i]['y_pos'];
23045 $x_repeat = $table['trbackground-images'][$i]['x_repeat'];
23046 $y_repeat = $table['trbackground-images'][$i]['y_repeat'];
23047 $resize = $table['trbackground-images'][$i]['resize'];
23048 $opacity = $table['trbackground-images'][$i]['opacity'];
23049 $itype = $table['trbackground-images'][$i]['itype'];
23050 $clippath = '';
23051 $gx = $x0;
23052 $gy = $y;
23053 $gh = $h;
23054 $gw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
23055 if ($table['borders_separate']) {
23056 $gw -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['padding']['R'] + $table['border_details']['R']['w'] + $table['border_spacing_H']);
23057 $clx = $x + ($table['border_spacing_H'] / 2);
23058 $cly = $y + ($table['border_spacing_V'] / 2);
23059 $clw = $w - $table['border_spacing_H'];
23060 $clh = $h - $table['border_spacing_V'];
23061 // Set clipping path
23062 $s = $this->_setClippingPath($clx, $cly, $clw, $clh); // mPDF 6
23063 $this->tableBackgrounds[$level * 9 + 5][] = ['x' => $gx + ($table['border_spacing_H'] / 2), 'y' => $gy + ($table['border_spacing_V'] / 2), 'w' => $gw - $table['border_spacing_V'], 'h' => $gh - $table['border_spacing_H'], 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => $s, 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
23064 } else {
23065 $this->tableBackgrounds[$level * 9 + 5][] = ['x' => $gx, 'y' => $gy, 'w' => $gw, 'h' => $gh, 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => '', 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
23066 }
23067 }
23068 }
23069 }
23070
23071 /* -- END BACKGROUNDS -- */
23072
23073 // TABLE BORDER - if separate
23074 if (($table['borders_separate'] || ($this->simpleTables && !$table['simple']['border'])) && $table['border']) {
23075 $halfspaceL = $table['padding']['L'] + ($table['border_spacing_H'] / 2);
23076 $halfspaceR = $table['padding']['R'] + ($table['border_spacing_H'] / 2);
23077 $halfspaceT = $table['padding']['T'] + ($table['border_spacing_V'] / 2);
23078 $halfspaceB = $table['padding']['B'] + ($table['border_spacing_V'] / 2);
23079 $tbx = $x;
23080 $tby = $y;
23081 $tbw = $w;
23082 $tbh = $h;
23083 $tab_bord = 0;
23084
23085 $corner = '';
23086 if ($i == 0) { // Top
23087 $tby -= $halfspaceT + ($table['border_details']['T']['w'] / 2);
23088 $tbh += $halfspaceT + ($table['border_details']['T']['w'] / 2);
23089 $this->setBorder($tab_bord, Border::TOP);
23090 $corner .= 'T';
23091 }
23092 if ($i == ($numrows - 1) || (isset($cell['rowspan']) && ($i + $cell['rowspan']) == $numrows)) { // Bottom
23093 $tbh += $halfspaceB + ($table['border_details']['B']['w'] / 2);
23094 $this->setBorder($tab_bord, Border::BOTTOM);
23095 $corner .= 'B';
23096 }
23097 if ($j == 0) { // Left
23098 $tbx -= $halfspaceL + ($table['border_details']['L']['w'] / 2);
23099 $tbw += $halfspaceL + ($table['border_details']['L']['w'] / 2);
23100 $this->setBorder($tab_bord, Border::LEFT);
23101 $corner .= 'L';
23102 }
23103 if ($j == ($numcols - 1) || (isset($cell['colspan']) && ($j + $cell['colspan']) == $numcols)) { // Right
23104 $tbw += $halfspaceR + ($table['border_details']['R']['w'] / 2);
23105 $this->setBorder($tab_bord, Border::RIGHT);
23106 $corner .= 'R';
23107 }
23108 $this->_tableRect($tbx, $tby, $tbw, $tbh, $tab_bord, $table['border_details'], false, $table['borders_separate'], 'table', $corner, $table['border_spacing_V'], $table['border_spacing_H']);
23109 }
23110
23111 unset($cell);
23112 // Reset values
23113 $this->Reset();
23114 }//end of (if isset(cells)...)
23115 }// end of columns
23116
23117 $newpagestarted = false;
23118 $this->tabletheadjustfinished = false;
23119
23120 /* -- COLUMNS -- */
23121 if ($this->ColActive) {
23122 if (!$this->table_keep_together && $i < $numrows - 1 && $level == 1) {
23123 $this->breakpoints[$this->CurrCol][] = $y + $h;
23124 } // mPDF 6
23125 if (count($this->cellBorderBuffer)) {
23126 $this->printcellbuffer();
23127 }
23128 }
23129 /* -- END COLUMNS -- */
23130
23131 if ($i == $numrows - 1) {
23132 $this->y = $y + $h;
23133 } // last row jump (update this->y position)
23134 if ($this->table_rotate && $level == 1) {
23135 $this->tbrot_h += $h;
23136 }
23137 } // end of rows
23138
23139 if (count($this->cellBorderBuffer)) {
23140 $this->printcellbuffer();
23141 }
23142
23143
23144 if ($this->tableClipPath) {
23145 $this->writer->write("Q");
23146 }
23147 $this->tableClipPath = '';
23148
23149 // Advance down page by half width of bottom border
23150 if ($table['borders_separate']) {
23151 $this->y += $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
23152 } else {
23153 $this->y += $table['max_cell_border_width']['B'] / 2;
23154 }
23155
23156 if ($table['borders_separate'] && $level == 1) {
23157 $this->tbrot_h += $table['margin']['B'] + $table['padding']['B'] + $table['border_details']['B']['w'] + $table['border_spacing_V'] / 2;
23158 } elseif ($level == 1) {
23159 $this->tbrot_h += $table['margin']['B'] + $table['max_cell_border_width']['B'] / 2;
23160 }
23161
23162 $bx = $x0;
23163 $by = $y0;
23164 if ($table['borders_separate']) {
23165 $bx -= ($table['padding']['L'] + $table['border_details']['L']['w'] + $table['border_spacing_H'] / 2);
23166 if ($tablestartpageno != $this->page) { // IF broken across page
23167 $by += $table['max_cell_border_width']['T'] / 2;
23168 if (empty($tableheader)) {
23169 $by -= ($table['border_spacing_V'] / 2);
23170 }
23171 } elseif ($split && $startrow > 0 && empty($tableheader)) {
23172 $by -= ($table['border_spacing_V'] / 2);
23173 } else {
23174 $by -= ($table['padding']['T'] + $table['border_details']['T']['w'] + $table['border_spacing_V'] / 2);
23175 }
23176 } elseif ($tablestartpageno != $this->page && !empty($tableheader)) {
23177 $by += $maxbwtop / 2;
23178 }
23179 $by -= $tableheaderadj;
23180 $bh = $this->y - $by;
23181 if (!$table['borders_separate']) {
23182 $bh -= $table['max_cell_border_width']['B'] / 2;
23183 }
23184
23185 if ($split) {
23186 $bw = 0;
23187 $finalSpread = true;
23188 for ($t = $startcol; $t < $numcols; $t++) {
23189 if ($table['colPg'][$t] == $splitpg) {
23190 $bw += $table['wc'][$t];
23191 }
23192 if ($table['colPg'][$t] > $splitpg) {
23193 $finalSpread = false;
23194 break;
23195 }
23196 }
23197 if ($startcol == 0) {
23198 $firstSpread = true;
23199 } else {
23200 $firstSpread = false;
23201 }
23202 if ($table['borders_separate']) {
23203 $bw += $table['border_spacing_H'];
23204 if ($firstSpread) {
23205 $bw += $table['padding']['L'] + $table['border_details']['L']['w'];
23206 } else {
23207 $bx += ($table['padding']['L'] + $table['border_details']['L']['w']);
23208 }
23209 if ($finalSpread) {
23210 $bw += $table['padding']['R'] + $table['border_details']['R']['w'];
23211 }
23212 }
23213 } else {
23214 $bw = $table['w'] - ($table['max_cell_border_width']['L'] / 2) - ($table['max_cell_border_width']['R'] / 2) - $table['margin']['L'] - $table['margin']['R'];
23215 }
23216
23217 if (!$this->ColActive) {
23218 if (isset($table['bgcolor'][-1])) {
23219 $color = $this->colorConverter->convert($table['bgcolor'][-1], $this->PDFAXwarnings);
23220 if ($color) {
23221 $this->tableBackgrounds[$level * 9][] = ['gradient' => false, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'col' => $color];
23222 }
23223 }
23224
23225 /* -- BACKGROUNDS -- */
23226 if (isset($table['gradient'])) {
23227 $g = $this->gradient->parseBackgroundGradient($table['gradient']);
23228 if ($g) {
23229 $this->tableBackgrounds[$level * 9 + 1][] = ['gradient' => true, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
23230 }
23231 }
23232
23233 if (isset($table['background-image'])) {
23234 if (isset($table['background-image']['gradient']) && $table['background-image']['gradient'] && preg_match('/(-moz-)*(repeating-)*(linear|radial)-gradient/', $table['background-image']['gradient'])) {
23235 $g = $this->gradient->parseMozGradient($table['background-image']['gradient']);
23236 if ($g) {
23237 $this->tableBackgrounds[$level * 9 + 1][] = ['gradient' => true, 'x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'gradtype' => $g['type'], 'stops' => $g['stops'], 'colorspace' => $g['colorspace'], 'coords' => $g['coords'], 'extend' => $g['extend'], 'clippath' => ''];
23238 }
23239 } else {
23240 $image_id = $table['background-image']['image_id'];
23241 $orig_w = $table['background-image']['orig_w'];
23242 $orig_h = $table['background-image']['orig_h'];
23243 $x_pos = $table['background-image']['x_pos'];
23244 $y_pos = $table['background-image']['y_pos'];
23245 $x_repeat = $table['background-image']['x_repeat'];
23246 $y_repeat = $table['background-image']['y_repeat'];
23247 $resize = $table['background-image']['resize'];
23248 $opacity = $table['background-image']['opacity'];
23249 $itype = $table['background-image']['itype'];
23250 $this->tableBackgrounds[$level * 9 + 2][] = ['x' => $bx, 'y' => $by, 'w' => $bw, 'h' => $bh, 'image_id' => $image_id, 'orig_w' => $orig_w, 'orig_h' => $orig_h, 'x_pos' => $x_pos, 'y_pos' => $y_pos, 'x_repeat' => $x_repeat, 'y_repeat' => $y_repeat, 'clippath' => '', 'resize' => $resize, 'opacity' => $opacity, 'itype' => $itype];
23251 }
23252 }
23253 /* -- END BACKGROUNDS -- */
23254 }
23255
23256 if ($this->tableBackgrounds && $level == 1) {
23257 $s = $this->PrintTableBackgrounds();
23258 if ($this->table_rotate && !$this->processingHeader && !$this->processingFooter) {
23259 $this->tablebuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->tablebuffer);
23260 if ($level == 1) {
23261 $this->tablebuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->tablebuffer);
23262 }
23263 } elseif ($this->bufferoutput) {
23264 $this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->headerbuffer);
23265 if ($level == 1) {
23266 $this->headerbuffer = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->headerbuffer);
23267 }
23268 } else {
23269 $this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', '\\1' . "\n" . $s . "\n", $this->pages[$this->page]);
23270 if ($level == 1) {
23271 $this->pages[$this->page] = preg_replace('/(___TABLE___BACKGROUNDS' . $this->uniqstr . ')/', " ", $this->pages[$this->page]);
23272 }
23273 }
23274 $this->tableBackgrounds = [];
23275 }
23276
23277
23278 // TABLE BOTTOM MARGIN
23279 if ($table['margin']['B']) {
23280 if (!$this->table_rotate && $level == 1) {
23281 $this->DivLn($table['margin']['B'], $this->blklvl, true); // collapsible
23282 } else {
23283 $this->y += ($table['margin']['B']);
23284 }
23285 }
23286
23287 if ($this->ColActive && $level == 1) {
23288 $this->breakpoints[$this->CurrCol][] = $this->y;
23289 } // *COLUMNS*
23290
23291 if ($split) {
23292 // Are there more columns to print on a next page?
23293 if ($lastCol < $numcols - 1) {
23294 $splitpg++;
23295 $startcol = $lastCol + 1;
23296 return [false, $startrow, $startcol, $splitpg, $returny, $y0];
23297 } else {
23298 return [true, 0, 0, 0, false, false];
23299 }
23300 }
23301 }
23302
23303 // END OF FUNCTION _tableWrite()
23305 /* -- END TABLES -- */
23306
23308 {
23309 for ($i = 1; $i <= count($this->extgstates); $i++) {
23310 $this->writer->object();
23311 $this->extgstates[$i]['n'] = $this->n;
23312 $this->writer->write('<</Type /ExtGState');
23313 foreach ($this->extgstates[$i]['parms'] as $k => $v) {
23314 $this->writer->write('/' . $k . ' ' . $v);
23315 }
23316 $this->writer->write('>>');
23317 $this->writer->write('endobj');
23318 }
23319 }
23320
23321 function SetProtection($permissions = [], $user_pass = '', $owner_pass = null, $length = 40)
23322 {
23323 $this->encrypted = $this->protection->setProtection($permissions, $user_pass, $owner_pass, $length);
23324 }
23325
23326 // =========================================
23327 // FROM class PDF_Bookmark
23328 function Bookmark($txt, $level = 0, $y = 0)
23329 {
23330 $txt = $this->purify_utf8_text($txt);
23331 if ($this->text_input_as_HTML) {
23332 $txt = $this->all_entities_to_utf8($txt);
23333 }
23334 if ($y == -1) {
23335 if (!$this->ColActive) {
23336 $y = $this->y;
23337 } else {
23338 $y = $this->y0;
23339 } // If columns are on - mark top of columns
23340 }
23341
23342 // else y is used as set, or =0 i.e. top of page
23343 // DIRECTIONALITY RTL
23344 $bmo = ['t' => $txt, 'l' => $level, 'y' => $y, 'p' => $this->page];
23345
23346 if ($this->keep_block_together) {
23347 // do nothing
23348 } elseif ($this->table_rotate) {
23349 $this->tbrot_BMoutlines[] = $bmo;
23350 } elseif ($this->kwt) {
23351 $this->kwt_BMoutlines[] = $bmo;
23352 } elseif ($this->ColActive) {
23353 $this->col_BMoutlines[] = $bmo;
23354 } else {
23355 $this->BMoutlines[] = $bmo;
23356 }
23357 }
23358
23362 function TOC(
23363 $tocfont = '',
23364 $tocfontsize = 0,
23365 $tocindent = 0,
23366 $resetpagenum = '',
23367 $pagenumstyle = '',
23368 $suppress = '',
23369 $toc_orientation = '',
23370 $TOCusePaging = true,
23371 $TOCuseLinking = false,
23372 $toc_id = 0,
23373 $tocoutdent = ''
23374 ) {
23375
23376 $this->tableOfContents->TOC(
23377 $tocfont,
23378 $tocfontsize,
23379 $tocindent,
23380 $resetpagenum,
23381 $pagenumstyle,
23382 $suppress,
23383 $toc_orientation,
23384 $TOCusePaging,
23385 $TOCuseLinking,
23386 $toc_id,
23387 $tocoutdent
23388 );
23389 }
23390
23392 {
23393 if (!is_array($a)) {
23394 $a = [];
23395 }
23396 $tocoutdent = (isset($a['tocoutdent']) ? $a['tocoutdent'] : (isset($a['outdent']) ? $a['outdent'] : ''));
23397 $TOCusePaging = (isset($a['TOCusePaging']) ? $a['TOCusePaging'] : (isset($a['paging']) ? $a['paging'] : true));
23398 $TOCuseLinking = (isset($a['TOCuseLinking']) ? $a['TOCuseLinking'] : (isset($a['links']) ? $a['links'] : ''));
23399 $toc_orientation = (isset($a['toc_orientation']) ? $a['toc_orientation'] : (isset($a['toc-orientation']) ? $a['toc-orientation'] : ''));
23400 $toc_mgl = (isset($a['toc_mgl']) ? $a['toc_mgl'] : (isset($a['toc-margin-left']) ? $a['toc-margin-left'] : ''));
23401 $toc_mgr = (isset($a['toc_mgr']) ? $a['toc_mgr'] : (isset($a['toc-margin-right']) ? $a['toc-margin-right'] : ''));
23402 $toc_mgt = (isset($a['toc_mgt']) ? $a['toc_mgt'] : (isset($a['toc-margin-top']) ? $a['toc-margin-top'] : ''));
23403 $toc_mgb = (isset($a['toc_mgb']) ? $a['toc_mgb'] : (isset($a['toc-margin-bottom']) ? $a['toc-margin-bottom'] : ''));
23404 $toc_mgh = (isset($a['toc_mgh']) ? $a['toc_mgh'] : (isset($a['toc-margin-header']) ? $a['toc-margin-header'] : ''));
23405 $toc_mgf = (isset($a['toc_mgf']) ? $a['toc_mgf'] : (isset($a['toc-margin-footer']) ? $a['toc-margin-footer'] : ''));
23406 $toc_ohname = (isset($a['toc_ohname']) ? $a['toc_ohname'] : (isset($a['toc-odd-header-name']) ? $a['toc-odd-header-name'] : ''));
23407 $toc_ehname = (isset($a['toc_ehname']) ? $a['toc_ehname'] : (isset($a['toc-even-header-name']) ? $a['toc-even-header-name'] : ''));
23408 $toc_ofname = (isset($a['toc_ofname']) ? $a['toc_ofname'] : (isset($a['toc-odd-footer-name']) ? $a['toc-odd-footer-name'] : ''));
23409 $toc_efname = (isset($a['toc_efname']) ? $a['toc_efname'] : (isset($a['toc-even-footer-name']) ? $a['toc-even-footer-name'] : ''));
23410 $toc_ohvalue = (isset($a['toc_ohvalue']) ? $a['toc_ohvalue'] : (isset($a['toc-odd-header-value']) ? $a['toc-odd-header-value'] : 0));
23411 $toc_ehvalue = (isset($a['toc_ehvalue']) ? $a['toc_ehvalue'] : (isset($a['toc-even-header-value']) ? $a['toc-even-header-value'] : 0));
23412 $toc_ofvalue = (isset($a['toc_ofvalue']) ? $a['toc_ofvalue'] : (isset($a['toc-odd-footer-value']) ? $a['toc-odd-footer-value'] : 0));
23413 $toc_efvalue = (isset($a['toc_efvalue']) ? $a['toc_efvalue'] : (isset($a['toc-even-footer-value']) ? $a['toc-even-footer-value'] : 0));
23414 $toc_preHTML = (isset($a['toc_preHTML']) ? $a['toc_preHTML'] : (isset($a['toc-preHTML']) ? $a['toc-preHTML'] : ''));
23415 $toc_postHTML = (isset($a['toc_postHTML']) ? $a['toc_postHTML'] : (isset($a['toc-postHTML']) ? $a['toc-postHTML'] : ''));
23416 $toc_bookmarkText = (isset($a['toc_bookmarkText']) ? $a['toc_bookmarkText'] : (isset($a['toc-bookmarkText']) ? $a['toc-bookmarkText'] : ''));
23417 $resetpagenum = (isset($a['resetpagenum']) ? $a['resetpagenum'] : '');
23418 $pagenumstyle = (isset($a['pagenumstyle']) ? $a['pagenumstyle'] : '');
23419 $suppress = (isset($a['suppress']) ? $a['suppress'] : '');
23420 $orientation = (isset($a['orientation']) ? $a['orientation'] : '');
23421 $mgl = (isset($a['mgl']) ? $a['mgl'] : (isset($a['margin-left']) ? $a['margin-left'] : ''));
23422 $mgr = (isset($a['mgr']) ? $a['mgr'] : (isset($a['margin-right']) ? $a['margin-right'] : ''));
23423 $mgt = (isset($a['mgt']) ? $a['mgt'] : (isset($a['margin-top']) ? $a['margin-top'] : ''));
23424 $mgb = (isset($a['mgb']) ? $a['mgb'] : (isset($a['margin-bottom']) ? $a['margin-bottom'] : ''));
23425 $mgh = (isset($a['mgh']) ? $a['mgh'] : (isset($a['margin-header']) ? $a['margin-header'] : ''));
23426 $mgf = (isset($a['mgf']) ? $a['mgf'] : (isset($a['margin-footer']) ? $a['margin-footer'] : ''));
23427 $ohname = (isset($a['ohname']) ? $a['ohname'] : (isset($a['odd-header-name']) ? $a['odd-header-name'] : ''));
23428 $ehname = (isset($a['ehname']) ? $a['ehname'] : (isset($a['even-header-name']) ? $a['even-header-name'] : ''));
23429 $ofname = (isset($a['ofname']) ? $a['ofname'] : (isset($a['odd-footer-name']) ? $a['odd-footer-name'] : ''));
23430 $efname = (isset($a['efname']) ? $a['efname'] : (isset($a['even-footer-name']) ? $a['even-footer-name'] : ''));
23431 $ohvalue = (isset($a['ohvalue']) ? $a['ohvalue'] : (isset($a['odd-header-value']) ? $a['odd-header-value'] : 0));
23432 $ehvalue = (isset($a['ehvalue']) ? $a['ehvalue'] : (isset($a['even-header-value']) ? $a['even-header-value'] : 0));
23433 $ofvalue = (isset($a['ofvalue']) ? $a['ofvalue'] : (isset($a['odd-footer-value']) ? $a['odd-footer-value'] : 0));
23434 $efvalue = (isset($a['efvalue']) ? $a['efvalue'] : (isset($a['even-footer-value']) ? $a['even-footer-value'] : 0));
23435 $toc_id = (isset($a['toc_id']) ? $a['toc_id'] : (isset($a['name']) ? $a['name'] : 0));
23436 $pagesel = (isset($a['pagesel']) ? $a['pagesel'] : (isset($a['pageselector']) ? $a['pageselector'] : ''));
23437 $toc_pagesel = (isset($a['toc_pagesel']) ? $a['toc_pagesel'] : (isset($a['toc-pageselector']) ? $a['toc-pageselector'] : ''));
23438 $sheetsize = (isset($a['sheetsize']) ? $a['sheetsize'] : (isset($a['sheet-size']) ? $a['sheet-size'] : ''));
23439 $toc_sheetsize = (isset($a['toc_sheetsize']) ? $a['toc_sheetsize'] : (isset($a['toc-sheet-size']) ? $a['toc-sheet-size'] : ''));
23440
23441 $this->TOCpagebreak('', '', '', $TOCusePaging, $TOCuseLinking, $toc_orientation, $toc_mgl, $toc_mgr, $toc_mgt, $toc_mgb, $toc_mgh, $toc_mgf, $toc_ohname, $toc_ehname, $toc_ofname, $toc_efname, $toc_ohvalue, $toc_ehvalue, $toc_ofvalue, $toc_efvalue, $toc_preHTML, $toc_postHTML, $toc_bookmarkText, $resetpagenum, $pagenumstyle, $suppress, $orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $toc_id, $pagesel, $toc_pagesel, $sheetsize, $toc_sheetsize, $tocoutdent);
23442 }
23443
23444 function TOCpagebreak($tocfont = '', $tocfontsize = '', $tocindent = '', $TOCusePaging = true, $TOCuseLinking = '', $toc_orientation = '', $toc_mgl = '', $toc_mgr = '', $toc_mgt = '', $toc_mgb = '', $toc_mgh = '', $toc_mgf = '', $toc_ohname = '', $toc_ehname = '', $toc_ofname = '', $toc_efname = '', $toc_ohvalue = 0, $toc_ehvalue = 0, $toc_ofvalue = 0, $toc_efvalue = 0, $toc_preHTML = '', $toc_postHTML = '', $toc_bookmarkText = '', $resetpagenum = '', $pagenumstyle = '', $suppress = '', $orientation = '', $mgl = '', $mgr = '', $mgt = '', $mgb = '', $mgh = '', $mgf = '', $ohname = '', $ehname = '', $ofname = '', $efname = '', $ohvalue = 0, $ehvalue = 0, $ofvalue = 0, $efvalue = 0, $toc_id = 0, $pagesel = '', $toc_pagesel = '', $sheetsize = '', $toc_sheetsize = '', $tocoutdent = '')
23445 {
23446 // Start a new page
23447 if ($this->state == 0) {
23448 $this->AddPage();
23449 }
23450 if ($this->y == $this->tMargin && (!$this->mirrorMargins || ($this->mirrorMargins && $this->page % 2 == 1))) {
23451 // Don't add a page
23452 if ($this->page == 1 && count($this->PageNumSubstitutions) == 0) {
23453 if (!$suppress) {
23454 $suppress = 'off';
23455 }
23456 // $this->PageNumSubstitutions[] = array('from'=>1, 'reset'=> $resetpagenum, 'type'=>$pagenumstyle, 'suppress'=> $suppress);
23457 }
23458 $this->PageNumSubstitutions[] = ['from' => $this->page, 'reset' => $resetpagenum, 'type' => $pagenumstyle, 'suppress' => $suppress];
23459 } else {
23460 $this->AddPage($orientation, 'NEXT-ODD', $resetpagenum, $pagenumstyle, $suppress, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $pagesel, $sheetsize);
23461 }
23462 $this->tableOfContents->TOCpagebreak($tocfont, $tocfontsize, $tocindent, $TOCusePaging, $TOCuseLinking, $toc_orientation, $toc_mgl, $toc_mgr, $toc_mgt, $toc_mgb, $toc_mgh, $toc_mgf, $toc_ohname, $toc_ehname, $toc_ofname, $toc_efname, $toc_ohvalue, $toc_ehvalue, $toc_ofvalue, $toc_efvalue, $toc_preHTML, $toc_postHTML, $toc_bookmarkText, $resetpagenum, $pagenumstyle, $suppress, $orientation, $mgl, $mgr, $mgt, $mgb, $mgh, $mgf, $ohname, $ehname, $ofname, $efname, $ohvalue, $ehvalue, $ofvalue, $efvalue, $toc_id, $pagesel, $toc_pagesel, $sheetsize, $toc_sheetsize, $tocoutdent);
23463 }
23464
23465 function TOC_Entry($txt, $level = 0, $toc_id = 0)
23466 {
23467 if ($this->ColActive) {
23468 $ily = $this->y0;
23469 } else {
23470 $ily = $this->y;
23471 } // use top of columns
23472
23473 $linkn = $this->AddLink();
23474 $uid = '__mpdfinternallink_' . $linkn;
23475 if ($this->table_rotate) {
23476 $this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page, "tbrot" => true];
23477 } elseif ($this->kwt) {
23478 $this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page, "kwt" => true];
23479 } elseif ($this->ColActive) {
23480 $this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page, "col" => $this->CurrCol];
23481 } elseif (!$this->keep_block_together) {
23482 $this->internallink[$uid] = ["Y" => $ily, "PAGE" => $this->page];
23483 }
23484 $this->internallink['#' . $uid] = $linkn;
23485 $this->SetLink($linkn, $ily, $this->page);
23486
23487 if (strtoupper($toc_id) == 'ALL') {
23488 $toc_id = '_mpdf_all';
23489 } elseif (!$toc_id) {
23490 $toc_id = 0;
23491 } else {
23492 $toc_id = strtolower($toc_id);
23493 }
23494 $btoc = ['t' => $txt, 'l' => $level, 'p' => $this->page, 'link' => $linkn, 'toc_id' => $toc_id];
23495 if ($this->keep_block_together) {
23496 // do nothing
23497 } /* -- TABLES -- */ elseif ($this->table_rotate) {
23498 $this->tbrot_toc[] = $btoc;
23499 } elseif ($this->kwt) {
23500 $this->kwt_toc[] = $btoc;
23501 } /* -- END TABLES -- */ elseif ($this->ColActive) { // *COLUMNS*
23502 $this->col_toc[] = $btoc; // *COLUMNS*
23503 } // *COLUMNS*
23504 else {
23505 $this->tableOfContents->_toc[] = $btoc;
23506 }
23507 }
23508
23509 /* -- END TOC -- */
23510
23511 // ======================================================
23512 function MovePages($target_page, $start_page, $end_page = -1)
23513 {
23514 // move a page/pages EARLIER in the document
23515 if ($end_page < 1) {
23516 $end_page = $start_page;
23517 }
23518 $n_toc = $end_page - $start_page + 1;
23519
23520 // Set/Update PageNumSubstitutions changes before moving anything
23521 if (count($this->PageNumSubstitutions)) {
23522 $tp_present = false;
23523 $sp_present = false;
23524 $ep_present = false;
23525 foreach ($this->PageNumSubstitutions as $k => $v) {
23526 if ($this->PageNumSubstitutions[$k]['from'] == $target_page) {
23527 $tp_present = true;
23528 if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
23529 $this->PageNumSubstitutions[$k]['suppress'] = 'off';
23530 }
23531 }
23532 if ($this->PageNumSubstitutions[$k]['from'] == $start_page) {
23533 $sp_present = true;
23534 if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
23535 $this->PageNumSubstitutions[$k]['suppress'] = 'off';
23536 }
23537 }
23538 if ($this->PageNumSubstitutions[$k]['from'] == ($end_page + 1)) {
23539 $ep_present = true;
23540 if ($this->PageNumSubstitutions[$k]['suppress'] != 'on' && $this->PageNumSubstitutions[$k]['suppress'] != 1) {
23541 $this->PageNumSubstitutions[$k]['suppress'] = 'off';
23542 }
23543 }
23544 }
23545
23546 if (!$tp_present) {
23547 list($tp_type, $tp_suppress, $tp_reset) = $this->docPageSettings($target_page);
23548 }
23549 if (!$sp_present) {
23550 list($sp_type, $sp_suppress, $sp_reset) = $this->docPageSettings($start_page);
23551 }
23552 if (!$ep_present) {
23553 list($ep_type, $ep_suppress, $ep_reset) = $this->docPageSettings($start_page - 1);
23554 }
23555 }
23556
23557 $last = [];
23558 // store pages
23559 for ($i = $start_page; $i <= $end_page; $i++) {
23560 $last[] = $this->pages[$i];
23561 }
23562 // move pages
23563 for ($i = $start_page - 1; $i >= ($target_page); $i--) {
23564 $this->pages[$i + $n_toc] = $this->pages[$i];
23565 }
23566 // Put toc pages at insert point
23567 for ($i = 0; $i < $n_toc; $i++) {
23568 $this->pages[$target_page + $i] = $last[$i];
23569 }
23570
23571 /* -- BOOKMARKS -- */
23572 // Update Bookmarks
23573 foreach ($this->BMoutlines as $i => $o) {
23574 if ($o['p'] >= $target_page) {
23575 $this->BMoutlines[$i]['p'] += $n_toc;
23576 }
23577 }
23578 /* -- END BOOKMARKS -- */
23579
23580 // Update Page Links
23581 if (count($this->PageLinks)) {
23582 $newarr = [];
23583 foreach ($this->PageLinks as $i => $o) {
23584 foreach ($this->PageLinks[$i] as $key => $pl) {
23585 if (strpos($pl[4], '@') === 0) {
23586 $p = substr($pl[4], 1);
23587 if ($p >= $start_page && $p <= $end_page) {
23588 $this->PageLinks[$i][$key][4] = '@' . ($p + ($target_page - $start_page));
23589 } elseif ($p >= $target_page && $p < $start_page) {
23590 $this->PageLinks[$i][$key][4] = '@' . ($p + $n_toc);
23591 }
23592 }
23593 }
23594 if ($i >= $start_page && $i <= $end_page) {
23595 $newarr[($i + ($target_page - $start_page))] = $this->PageLinks[$i];
23596 } elseif ($i >= $target_page && $i < $start_page) {
23597 $newarr[($i + $n_toc)] = $this->PageLinks[$i];
23598 } else {
23599 $newarr[$i] = $this->PageLinks[$i];
23600 }
23601 }
23602 $this->PageLinks = $newarr;
23603 }
23604
23605 // OrientationChanges
23606 if (count($this->OrientationChanges)) {
23607 $newarr = [];
23608 foreach ($this->OrientationChanges as $p => $v) {
23609 if ($p >= $start_page && $p <= $end_page) {
23610 $newarr[($p + ($target_page - $start_page))] = $this->OrientationChanges[$p];
23611 } elseif ($p >= $target_page && $p < $start_page) {
23612 $newarr[$p + $n_toc] = $this->OrientationChanges[$p];
23613 } else {
23614 $newarr[$p] = $this->OrientationChanges[$p];
23615 }
23616 }
23617 ksort($newarr);
23618 $this->OrientationChanges = $newarr;
23619 }
23620
23621 // Page Dimensions
23622 if (count($this->pageDim)) {
23623 $newarr = [];
23624 foreach ($this->pageDim as $p => $v) {
23625 if ($p >= $start_page && $p <= $end_page) {
23626 $newarr[($p + ($target_page - $start_page))] = $this->pageDim[$p];
23627 } elseif ($p >= $target_page && $p < $start_page) {
23628 $newarr[$p + $n_toc] = $this->pageDim[$p];
23629 } else {
23630 $newarr[$p] = $this->pageDim[$p];
23631 }
23632 }
23633 ksort($newarr);
23634 $this->pageDim = $newarr;
23635 }
23636
23637 // HTML Headers & Footers
23638 if (count($this->saveHTMLHeader)) {
23639 $newarr = [];
23640 foreach ($this->saveHTMLHeader as $p => $v) {
23641 if ($p >= $start_page && $p <= $end_page) {
23642 $newarr[($p + ($target_page - $start_page))] = $this->saveHTMLHeader[$p];
23643 } elseif ($p >= $target_page && $p < $start_page) {
23644 $newarr[$p + $n_toc] = $this->saveHTMLHeader[$p];
23645 } else {
23646 $newarr[$p] = $this->saveHTMLHeader[$p];
23647 }
23648 }
23649 ksort($newarr);
23650 $this->saveHTMLHeader = $newarr;
23651 }
23652 if (count($this->saveHTMLFooter)) {
23653 $newarr = [];
23654 foreach ($this->saveHTMLFooter as $p => $v) {
23655 if ($p >= $start_page && $p <= $end_page) {
23656 $newarr[($p + ($target_page - $start_page))] = $this->saveHTMLFooter[$p];
23657 } elseif ($p >= $target_page && $p < $start_page) {
23658 $newarr[$p + $n_toc] = $this->saveHTMLFooter[$p];
23659 } else {
23660 $newarr[$p] = $this->saveHTMLFooter[$p];
23661 }
23662 }
23663 ksort($newarr);
23664 $this->saveHTMLFooter = $newarr;
23665 }
23666
23667 // Update Internal Links
23668 if (count($this->internallink)) {
23669 foreach ($this->internallink as $key => $o) {
23670 if (is_array($o) && $o['PAGE'] >= $start_page && $o['PAGE'] <= $end_page) {
23671 $this->internallink[$key]['PAGE'] += ($target_page - $start_page);
23672 } elseif (is_array($o) && $o['PAGE'] >= $target_page && $o['PAGE'] < $start_page) {
23673 $this->internallink[$key]['PAGE'] += $n_toc;
23674 }
23675 }
23676 }
23677
23678 // Update Links
23679 if (count($this->links)) {
23680 foreach ($this->links as $key => $o) {
23681 if ($o[0] >= $start_page && $o[0] <= $end_page) {
23682 $this->links[$key][0] += ($target_page - $start_page);
23683 }
23684 if ($o[0] >= $target_page && $o[0] < $start_page) {
23685 $this->links[$key][0] += $n_toc;
23686 }
23687 }
23688 }
23689
23690 // Update Form fields
23691 if (count($this->form->forms)) {
23692 foreach ($this->form->forms as $key => $f) {
23693 if ($f['page'] >= $start_page && $f['page'] <= $end_page) {
23694 $this->form->forms[$key]['page'] += ($target_page - $start_page);
23695 }
23696 if ($f['page'] >= $target_page && $f['page'] < $start_page) {
23697 $this->form->forms[$key]['page'] += $n_toc;
23698 }
23699 }
23700 }
23701
23702 /* -- ANNOTATIONS -- */
23703 // Update Annotations
23704 if (count($this->PageAnnots)) {
23705 $newarr = [];
23706 foreach ($this->PageAnnots as $p => $anno) {
23707 if ($p >= $start_page && $p <= $end_page) {
23708 $np = $p + ($target_page - $start_page);
23709 foreach ($anno as $o) {
23710 $newarr[$np][] = $o;
23711 }
23712 } elseif ($p >= $target_page && $p < $start_page) {
23713 $np = $p + $n_toc;
23714 foreach ($anno as $o) {
23715 $newarr[$np][] = $o;
23716 }
23717 } else {
23718 $newarr[$p] = $this->PageAnnots[$p];
23719 }
23720 }
23721 $this->PageAnnots = $newarr;
23722 unset($newarr);
23723 }
23724 /* -- END ANNOTATIONS -- */
23725
23726 // Update TOC pages
23727 if (count($this->tableOfContents->_toc)) {
23728 foreach ($this->tableOfContents->_toc as $key => $t) {
23729 if ($t['p'] >= $start_page && $t['p'] <= $end_page) {
23730 $this->tableOfContents->_toc[$key]['p'] += ($target_page - $start_page);
23731 }
23732 if ($t['p'] >= $target_page && $t['p'] < $start_page) {
23733 $this->tableOfContents->_toc[$key]['p'] += $n_toc;
23734 }
23735 }
23736 }
23737
23738 // Update PageNumSubstitutions
23739 if (count($this->PageNumSubstitutions)) {
23740 $newarr = [];
23741 foreach ($this->PageNumSubstitutions as $k => $v) {
23742 if ($this->PageNumSubstitutions[$k]['from'] >= $start_page && $this->PageNumSubstitutions[$k]['from'] <= $end_page) {
23743 $this->PageNumSubstitutions[$k]['from'] += ($target_page - $start_page);
23744 $newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
23745 } elseif ($this->PageNumSubstitutions[$k]['from'] >= $target_page && $this->PageNumSubstitutions[$k]['from'] < $start_page) {
23746 $this->PageNumSubstitutions[$k]['from'] += $n_toc;
23747 $newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
23748 } else {
23749 $newarr[$this->PageNumSubstitutions[$k]['from']] = $this->PageNumSubstitutions[$k];
23750 }
23751 }
23752
23753 if (!$sp_present) {
23754 $newarr[$target_page] = ['from' => $target_page, 'suppress' => $sp_suppress, 'reset' => $sp_reset, 'type' => $sp_type];
23755 }
23756 if (!$tp_present) {
23757 $newarr[($target_page + $n_toc)] = ['from' => ($target_page + $n_toc), 'suppress' => $tp_suppress, 'reset' => $tp_reset, 'type' => $tp_type];
23758 }
23759 if (!$ep_present && $end_page > count($this->pages)) {
23760 $newarr[($end_page + 1)] = ['from' => ($end_page + 1), 'suppress' => $ep_suppress, 'reset' => $ep_reset, 'type' => $ep_type];
23761 }
23762 ksort($newarr);
23763 $this->PageNumSubstitutions = [];
23764 foreach ($newarr as $v) {
23765 $this->PageNumSubstitutions[] = $v;
23766 }
23767 }
23768 }
23769
23770 function DeletePages($start_page, $end_page = -1)
23771 {
23772 // move a page/pages EARLIER in the document
23773 if ($end_page < 1) {
23774 $end_page = $start_page;
23775 }
23776 $n_tod = $end_page - $start_page + 1;
23777 $last_page = count($this->pages);
23778 $n_atend = $last_page - $end_page + 1;
23779
23780 // move pages
23781 for ($i = 0; $i < $n_atend; $i++) {
23782 $this->pages[$start_page + $i] = $this->pages[$end_page + 1 + $i];
23783 }
23784 // delete pages
23785 for ($i = 0; $i < $n_tod; $i++) {
23786 unset($this->pages[$last_page - $i]);
23787 }
23788
23789
23790 /* -- BOOKMARKS -- */
23791 // Update Bookmarks
23792 foreach ($this->BMoutlines as $i => $o) {
23793 if ($o['p'] >= $end_page) {
23794 $this->BMoutlines[$i]['p'] -= $n_tod;
23795 } elseif ($p < $start_page) {
23796 unset($this->BMoutlines[$i]);
23797 }
23798 }
23799 /* -- END BOOKMARKS -- */
23800
23801 // Update Page Links
23802 if (count($this->PageLinks)) {
23803 $newarr = [];
23804 foreach ($this->PageLinks as $i => $o) {
23805 foreach ($this->PageLinks[$i] as $key => $pl) {
23806 if (strpos($pl[4], '@') === 0) {
23807 $p = substr($pl[4], 1);
23808 if ($p > $end_page) {
23809 $this->PageLinks[$i][$key][4] = '@' . ($p - $n_tod);
23810 } elseif ($p < $start_page) {
23811 unset($this->PageLinks[$i][$key]);
23812 }
23813 }
23814 }
23815 if ($i > $end_page) {
23816 $newarr[($i - $n_tod)] = $this->PageLinks[$i];
23817 } elseif ($p < $start_page) {
23818 $newarr[$i] = $this->PageLinks[$i];
23819 }
23820 }
23821 $this->PageLinks = $newarr;
23822 }
23823
23824 // OrientationChanges
23825 if (count($this->OrientationChanges)) {
23826 $newarr = [];
23827 foreach ($this->OrientationChanges as $p => $v) {
23828 if ($p > $end_page) {
23829 $newarr[($p - $t_tod)] = $this->OrientationChanges[$p];
23830 } elseif ($p < $start_page) {
23831 $newarr[$p] = $this->OrientationChanges[$p];
23832 }
23833 }
23834 ksort($newarr);
23835 $this->OrientationChanges = $newarr;
23836 }
23837
23838 // Page Dimensions
23839 if (count($this->pageDim)) {
23840 $newarr = [];
23841 foreach ($this->pageDim as $p => $v) {
23842 if ($p > $end_page) {
23843 $newarr[($p - $n_tod)] = $this->pageDim[$p];
23844 } elseif ($p < $start_page) {
23845 $newarr[$p] = $this->pageDim[$p];
23846 }
23847 }
23848 ksort($newarr);
23849 $this->pageDim = $newarr;
23850 }
23851
23852 // HTML Headers & Footers
23853 if (count($this->saveHTMLHeader)) {
23854 foreach ($this->saveHTMLHeader as $p => $v) {
23855 if ($p > $end_page) {
23856 $newarr[($p - $n_tod)] = $this->saveHTMLHeader[$p];
23857 } // mPDF 5.7.3
23858 elseif ($p < $start_page) {
23859 $newarr[$p] = $this->saveHTMLHeader[$p];
23860 }
23861 }
23862 ksort($newarr);
23863 $this->saveHTMLHeader = $newarr;
23864 }
23865 if (count($this->saveHTMLFooter)) {
23866 $newarr = [];
23867 foreach ($this->saveHTMLFooter as $p => $v) {
23868 if ($p > $end_page) {
23869 $newarr[($p - $n_tod)] = $this->saveHTMLFooter[$p];
23870 } elseif ($p < $start_page) {
23871 $newarr[$p] = $this->saveHTMLFooter[$p];
23872 }
23873 }
23874 ksort($newarr);
23875 $this->saveHTMLFooter = $newarr;
23876 }
23877
23878 // Update Internal Links
23879 foreach ($this->internallink as $key => $o) {
23880 if ($o['PAGE'] > $end_page) {
23881 $this->internallink[$key]['PAGE'] -= $n_tod;
23882 } elseif ($o['PAGE'] < $start_page) {
23883 unset($this->internallink[$key]);
23884 }
23885 }
23886
23887 // Update Links
23888 foreach ($this->links as $key => $o) {
23889 if ($o[0] > $end_page) {
23890 $this->links[$key][0] -= $n_tod;
23891 } elseif ($o[0] < $start_page) {
23892 unset($this->links[$key]);
23893 }
23894 }
23895
23896 // Update Form fields
23897 foreach ($this->form->forms as $key => $f) {
23898 if ($f['page'] > $end_page) {
23899 $this->form->forms[$key]['page'] -= $n_tod;
23900 } elseif ($f['page'] < $start_page) {
23901 unset($this->form->forms[$key]);
23902 }
23903 }
23904
23905 /* -- ANNOTATIONS -- */
23906 // Update Annotations
23907 if (count($this->PageAnnots)) {
23908 $newarr = [];
23909 foreach ($this->PageAnnots as $p => $anno) {
23910 if ($p > $end_page) {
23911 foreach ($anno as $o) {
23912 $newarr[($p - $n_tod)][] = $o;
23913 }
23914 } elseif ($p < $start_page) {
23915 $newarr[$p] = $this->PageAnnots[$p];
23916 }
23917 }
23918 ksort($newarr);
23919 $this->PageAnnots = $newarr;
23920 }
23921 /* -- END ANNOTATIONS -- */
23922
23923 // Update PageNumSubstitutions
23924 foreach ($this->PageNumSubstitutions as $k => $v) {
23925 if ($this->PageNumSubstitutions[$k]['from'] > $end_page) {
23926 $this->PageNumSubstitutions[$k]['from'] -= $n_tod;
23927 } elseif ($this->PageNumSubstitutions[$k]['from'] < $start_page) {
23928 unset($this->PageNumSubstitutions[$k]);
23929 }
23930 }
23931
23932 unset($newarr);
23933 $this->page = count($this->pages);
23934 }
23935
23936 // ======================================================
23937 /* -- INDEX -- */
23938 // FROM class PDF_Ref == INDEX
23939
23940 function IndexEntry($txt, $xref = '')
23941 {
23942 if ($xref) {
23943 $this->IndexEntrySee($txt, $xref);
23944 return;
23945 }
23946
23947 // Search the reference (AND Ref/PageNo) in the array
23948 $Present = false;
23949 if ($this->keep_block_together) {
23950 // do nothing
23951 } /* -- TABLES -- */ elseif ($this->kwt) {
23952 $size = count($this->kwt_Reference);
23953 for ($i = 0; $i < $size; $i++) {
23954 if (isset($this->kwt_Reference[$i]['t']) && $this->kwt_Reference[$i]['t'] == $txt) {
23955 $Present = true;
23956 if ($this->page != $this->kwt_Reference[$i]['op']) {
23957 $this->kwt_Reference[$i]['op'] = $this->page;
23958 }
23959 }
23960 }
23961 if (!$Present) { // If not found, add it
23962 $this->kwt_Reference[] = ['t' => $txt, 'op' => $this->page];
23963 }
23964 } /* -- END TABLES -- */ else {
23965 $size = count($this->Reference);
23966 for ($i = 0; $i < $size; $i++) {
23967 if (isset($this->Reference[$i]['t']) && $this->Reference[$i]['t'] == $txt) {
23968 $Present = true;
23969 if (!in_array($this->page, $this->Reference[$i]['p'])) {
23970 $this->Reference[$i]['p'][] = $this->page;
23971 }
23972 }
23973 }
23974 if (!$Present) { // If not found, add it
23975 $this->Reference[] = ['t' => $txt, 'p' => [$this->page]];
23976 }
23977 }
23978 }
23979
23980 // Added function to add a reference "Elephants. See Chickens"
23981 function IndexEntrySee($txta, $txtb)
23982 {
23983 if ($this->directionality == 'rtl') { // *OTL*
23984 // ONLY DO THIS IF NOT IN TAGS
23985 if ($txta == strip_tags($txta)) {
23986 $txta = str_replace(':', ' - ', $txta); // *OTL*
23987 }
23988 if ($txtb == strip_tags($txtb)) {
23989 $txtb = str_replace(':', ' - ', $txtb); // *OTL*
23990 }
23991 } // *OTL*
23992 else { // *OTL*
23993 if ($txta == strip_tags($txta)) {
23994 $txta = str_replace(':', ', ', $txta);
23995 }
23996 if ($txtb == strip_tags($txtb)) {
23997 $txtb = str_replace(':', ', ', $txtb);
23998 }
23999 } // *OTL*
24000 $this->Reference[] = ['t' => $txta . ' - see ' . $txtb, 'p' => []];
24001 }
24002
24003 private function filesInDir($directory)
24004 {
24005 $files = [];
24006 foreach ((new \DirectoryIterator($directory)) as $v) {
24007 if ($v->isDir() || $v->isDot()) {
24008 continue;
24009 }
24010
24011 $files[] = $v->getPathname();
24012 }
24013
24014 return $files;
24015 }
24016
24017 function InsertIndex($usedivletters = 1, $useLinking = false, $indexCollationLocale = '', $indexCollationGroup = '')
24018 {
24019 $size = count($this->Reference);
24020 if ($size == 0) {
24021 return false;
24022 }
24023
24024 // $spacer used after named entry
24025 // $sep separates number [groups], $joiner joins numbers in range
24026 // e.g. "elephant 73, 97-99" = elephant[$spacer]73[$sep]97[$joiner]99
24027 // $subEntrySeparator separates main and subentry (if $this->indexUseSubentries == false;) e.g.
24028 // Mammal:elephant => Mammal[$subEntrySeparator]elephant
24029 // $subEntryInset specifies what precedes a subentry (if $this->indexUseSubentries == true;) e.g.
24030 // Mammal:elephant => [$subEntryInset]elephant
24031 $spacer = "\xc2\xa0 ";
24032 if ($this->directionality == 'rtl') {
24033 $sep = '&#x060c; ';
24034 $joiner = '-';
24035 $subEntrySeparator = '&#x060c; ';
24036 $subEntryInset = ' - ';
24037 } else {
24038 $sep = ', ';
24039 $joiner = '-';
24040 $subEntrySeparator = ', ';
24041 $subEntryInset = ' - ';
24042 }
24043
24044 for ($i = 0; $i < $size; $i++) {
24045 $txt = $this->Reference[$i]['t'];
24046 $txt = strip_tags($txt); // mPDF 6
24047 $txt = $this->purify_utf8($txt);
24048 $this->Reference[$i]['uf'] = $txt; // Unformatted e.g. pure utf-8 encoded characters, no mark-up/tags
24049 // Used for ordering and collation
24050 }
24051
24052 if ($usedivletters) {
24053 if ($indexCollationGroup && \in_array(strtolower($indexCollationGroup), array_map(function ($v) {
24054 return strtolower(basename($v, '.php'));
24055 }, $this->filesInDir(__DIR__ . '/../data/collations/')))) {
24056 $collation = require __DIR__ . '/../data/collations/' . $indexCollationGroup . '.php';
24057 } else {
24058 $collation = [];
24059 }
24060 for ($i = 0; $i < $size; $i++) {
24061 if ($this->Reference[$i]['uf']) {
24062 $l = mb_substr($this->Reference[$i]['uf'], 0, 1, 'UTF-8');
24063 if (isset($indexCollationGroup) && $indexCollationGroup) {
24064 $uni = $this->UTF8StringToArray($l);
24065 $ucode = $uni[0];
24066 if (isset($collation[$ucode])) {
24067 $this->Reference[$i]['d'] = UtfString::code2utf($collation[$ucode]);
24068 } else {
24069 $this->Reference[$i]['d'] = mb_strtolower($l, 'UTF-8');
24070 }
24071 } else {
24072 $this->Reference[$i]['d'] = mb_strtolower($l, 'UTF-8');
24073 }
24074 }
24075 }
24076 }
24077
24078 // Alphabetic sort of the references
24079 $originalLocale = setlocale(LC_COLLATE, 0);
24080 if ($indexCollationLocale) {
24081 setlocale(LC_COLLATE, $indexCollationLocale);
24082 }
24083
24084 usort($this->Reference, function ($a, $b) {
24085 return strcoll(strtolower($a['uf']), strtolower($b['uf']));
24086 });
24087
24088 if ($indexCollationLocale) {
24089 setlocale(LC_COLLATE, $originalLocale);
24090 }
24091
24092 $html = '<div class="mpdf_index_main">';
24093
24094 $lett = '';
24095 $last_lett = '';
24096 $mainentry = '';
24097 for ($i = 0; $i < $size; $i++) {
24098 if ($this->Reference[$i]['t']) {
24099 if ($usedivletters) {
24100 $lett = $this->Reference[$i]['d'];
24101 if ($lett != $last_lett) {
24102 $html .= '<div class="mpdf_index_letter">' . $lett . '</div>';
24103 }
24104 }
24105 $txt = $this->Reference[$i]['t'];
24106
24107 // Sub-entries e.g. Mammals:elephant
24108 // But allow for tags e.g. <b>Mammal</b>:elephants
24109 $a = preg_split('/(<.*?>)/', $txt, -1, PREG_SPLIT_DELIM_CAPTURE);
24110 $txt = '';
24111 $marker = false;
24112 foreach ($a as $k => $e) {
24113 if ($k % 2 == 0 && !$marker) {
24114 if (strpos($e, ':') !== false) { // == SubEntry
24115 if ($this->indexUseSubentries) {
24116 // If the Main entry does not have any page numbers associated with it
24117 // create and insert an entry
24118 list($txtmain, $sub) = preg_split('/[:]/', $e, 2);
24119 if (strip_tags($txt . $txtmain) != $mainentry) {
24120 $html .= '<div class="mpdf_index_entry">' . $txt . $txtmain . '</div>';
24121 $mainentry = strip_tags($txt . $txtmain);
24122 }
24123
24124 $txt = $subEntryInset;
24125 $e = $sub; // Only replace first one
24126 } else {
24127 $e = preg_replace('/[:]/', $subEntrySeparator, $e, 1); // Only replace first one
24128 }
24129 $marker = true; // Don't replace any more once the subentry marker has been found
24130 }
24131 }
24132 $txt .= $e;
24133 }
24134
24135 if (!$marker) {
24136 $mainentry = strip_tags($txt);
24137 }
24138
24139 $html .= '<div class="mpdf_index_entry">';
24140 $html .= $txt;
24141 $ppp = $this->Reference[$i]['p']; // = array of page numbers to point to
24142 if (count($ppp)) {
24143 sort($ppp);
24144 $newarr = [];
24145 $range_start = $ppp[0];
24146 $range_end = 0;
24147
24148 $html .= $spacer;
24149
24150 for ($zi = 1; $zi < count($ppp); $zi++) {
24151 if ($ppp[$zi] == ($ppp[($zi - 1)] + 1)) {
24152 $range_end = $ppp[$zi];
24153 } else {
24154 if ($range_end) {
24155 if ($range_end == $range_start + 1) {
24156 if ($useLinking) {
24157 $html .= '<a class="mpdf_index_link" href="@' . $range_start . '">';
24158 }
24159 $html .= $this->docPageNum($range_start);
24160 if ($useLinking) {
24161 $html .= '</a>';
24162 }
24163 $html .= $sep;
24164
24165 if ($useLinking) {
24166 $html .= '<a class="mpdf_index_link" href="@' . $ppp[$zi - 1] . '">';
24167 }
24168 $html .= $this->docPageNum($ppp[$zi - 1]);
24169 if ($useLinking) {
24170 $html .= '</a>';
24171 }
24172 $html .= $sep;
24173 }
24174 } else {
24175 if ($useLinking) {
24176 $html .= '<a class="mpdf_index_link" href="@' . $ppp[$zi - 1] . '">';
24177 }
24178 $html .= $this->docPageNum($ppp[$zi - 1]);
24179 if ($useLinking) {
24180 $html .= '</a>';
24181 }
24182 $html .= $sep;
24183 }
24184 $range_start = $ppp[$zi];
24185 $range_end = 0;
24186 }
24187 }
24188
24189 if ($range_end) {
24190 if ($useLinking) {
24191 $html .= '<a class="mpdf_index_link" href="@' . $range_start . '">';
24192 }
24193 $html .= $this->docPageNum($range_start);
24194 if ($range_end == $range_start + 1) {
24195 if ($useLinking) {
24196 $html .= '</a>';
24197 }
24198 $html .= $sep;
24199 if ($useLinking) {
24200 $html .= '<a class="mpdf_index_link" href="@' . $range_end . '">';
24201 }
24202 $html .= $this->docPageNum($range_end);
24203 if ($useLinking) {
24204 $html .= '</a>';
24205 }
24206 } else {
24207 $html .= $joiner;
24208 $html .= $this->docPageNum($range_end);
24209 if ($useLinking) {
24210 $html .= '</a>';
24211 }
24212 }
24213 } else {
24214 if ($useLinking) {
24215 $html .= '<a class="mpdf_index_link" href="@' . $ppp[(count($ppp) - 1)] . '">';
24216 }
24217 $html .= $this->docPageNum($ppp[(count($ppp) - 1)]);
24218 if ($useLinking) {
24219 $html .= '</a>';
24220 }
24221 }
24222 }
24223 }
24224 $html .= '</div>';
24225 $last_lett = $lett;
24226 }
24227 $html .= '</div>';
24228 $save_fpb = $this->fixedPosBlockSave;
24229 $this->WriteHTML($html);
24230 $this->fixedPosBlockSave = $save_fpb;
24231
24232 $this->breakpoints[$this->CurrCol][] = $this->y; // *COLUMNS*
24233 }
24234
24235 /* -- END INDEX -- */
24236
24238 {
24239 if (count($this->cellBorderBuffer)) {
24240 $this->printcellbuffer();
24241 } // *TABLES*
24242 /* -- COLUMNS -- */
24243 if ($this->ColActive == 1) {
24244 if ($this->CurrCol < $this->NbCol - 1) {
24245 // Go to the next column
24246 $this->CurrCol++;
24247 $this->SetCol($this->CurrCol);
24248 $this->y = $this->y0;
24249 $this->ChangeColumn = 1; // Number (and direction) of columns changed +1, +2, -2 etc.
24250 // DIRECTIONALITY RTL
24251 if ($this->directionality == 'rtl') {
24252 $this->ChangeColumn = -($this->ChangeColumn);
24253 } // *OTL*
24254 // Stay on the page
24255 return false;
24256 } else {
24257 // Go back to the first column - NEW PAGE
24258 if (count($this->columnbuffer)) {
24259 $this->printcolumnbuffer();
24260 }
24261 $this->SetCol(0);
24262 $this->y0 = $this->tMargin;
24263 $this->ChangeColumn = -($this->NbCol - 1);
24264 // DIRECTIONALITY RTL
24265 if ($this->directionality == 'rtl') {
24266 $this->ChangeColumn = -($this->ChangeColumn);
24267 } // *OTL*
24268 // Page break
24269 return true;
24270 }
24271 } /* -- END COLUMNS -- */
24272 /* -- TABLES -- */ elseif ($this->table_rotate) {
24273 if ($this->tablebuffer) {
24274 $this->printtablebuffer();
24275 }
24276 return true;
24277 } /* -- END TABLES -- */ else { // *COLUMNS*
24278 $this->ChangeColumn = 0;
24279 return $this->autoPageBreak;
24280 } // *COLUMNS*
24281 return $this->autoPageBreak;
24282 }
24283
24284 // ----------- COLUMNS ---------------------
24285 /* -- COLUMNS -- */
24286
24287 function SetColumns($NbCol, $vAlign = '', $gap = 5)
24288 {
24289 // NbCol = number of columns
24290 // Anything less than 2 turns columns off
24291 if ($NbCol < 2) { // SET COLUMNS OFF
24292 if ($this->ColActive) {
24293 $this->ColActive = 0;
24294 if (count($this->columnbuffer)) {
24295 $this->printcolumnbuffer();
24296 }
24297 $this->NbCol = 1;
24298 $this->ResetMargins();
24299 $this->pgwidth = $this->w - $this->lMargin - $this->rMargin;
24300 $this->divwidth = 0;
24301 $this->Ln();
24302 }
24303 $this->ColActive = 0;
24304 $this->columnbuffer = [];
24305 $this->ColDetails = [];
24306 $this->columnLinks = [];
24307 $this->columnAnnots = [];
24308 $this->columnForms = [];
24309 $this->col_BMoutlines = [];
24310 $this->col_toc = [];
24311 $this->breakpoints = [];
24312 } else { // SET COLUMNS ON
24313 if ($this->ColActive) {
24314 $this->ColActive = 0;
24315 if (count($this->columnbuffer)) {
24316 $this->printcolumnbuffer();
24317 }
24318 $this->ResetMargins();
24319 }
24320 if (isset($this->y) && $this->y > $this->tMargin) {
24321 $this->Ln();
24322 }
24323 $this->NbCol = $NbCol;
24324 $this->ColGap = $gap;
24325 $this->divwidth = 0;
24326 $this->ColActive = 1;
24327 $this->ColumnAdjust = true; // enables column height adjustment for the page
24328 $this->columnbuffer = [];
24329 $this->ColDetails = [];
24330 $this->columnLinks = [];
24331 $this->columnAnnots = [];
24332 $this->columnForms = [];
24333 $this->col_BMoutlines = [];
24334 $this->col_toc = [];
24335 $this->breakpoints = [];
24336 if ((strtoupper($vAlign) == 'J') || (strtoupper($vAlign) == 'JUSTIFY')) {
24337 $vAlign = 'J';
24338 } else {
24339 $vAlign = '';
24340 }
24341 $this->colvAlign = $vAlign;
24342 // Save the ordinate
24343 $absL = $this->DeflMargin - ($gap / 2);
24344 $absR = $this->DefrMargin - ($gap / 2);
24345 $PageWidth = $this->w - $absL - $absR; // virtual pagewidth for calculation only
24346 $ColWidth = (($PageWidth - ($gap * ($NbCol))) / $NbCol);
24347 $this->ColWidth = $ColWidth;
24348 /* -- OTL -- */
24349
24350 if ($this->directionality == 'rtl') {
24351 for ($i = 0; $i < $this->NbCol; $i++) {
24352 $this->ColL[$i] = $absL + ($gap / 2) + (($NbCol - ($i + 1)) * ($PageWidth / $NbCol));
24353 $this->ColR[$i] = $this->ColL[$i] + $ColWidth; // NB This is not R margin -> R pos
24354 }
24355 } else {
24356 /* -- END OTL -- */
24357 for ($i = 0; $i < $this->NbCol; $i++) {
24358 $this->ColL[$i] = $absL + ($gap / 2) + ($i * ($PageWidth / $NbCol) );
24359 $this->ColR[$i] = $this->ColL[$i] + $ColWidth; // NB This is not R margin -> R pos
24360 }
24361 } // *OTL*
24362 $this->pgwidth = $ColWidth;
24363 $this->SetCol(0);
24364 $this->y0 = $this->y;
24365 }
24366 $this->x = $this->lMargin;
24367 }
24368
24369 function SetCol($CurrCol)
24370 {
24371 // Used internally to set column by number: 0 is 1st column
24372 // Set position on a column
24373 $this->CurrCol = $CurrCol;
24374 $x = $this->ColL[$CurrCol];
24375 $xR = $this->ColR[$CurrCol]; // NB This is not R margin -> R pos
24376 if (($this->mirrorMargins) && (($this->page) % 2 == 0)) { // EVEN
24377 $x += $this->MarginCorrection;
24378 $xR += $this->MarginCorrection;
24379 }
24380 $this->SetMargins($x, ($this->w - $xR), $this->tMargin);
24381 }
24382
24383 function AddColumn()
24384 {
24385 $this->NewColumn();
24386 $this->ColumnAdjust = false; // disables all column height adjustment for the page.
24387 }
24388
24389 function NewColumn()
24390 {
24391 if ($this->ColActive == 1) {
24392 if ($this->CurrCol < $this->NbCol - 1) {
24393 // Go to the next column
24394 $this->CurrCol++;
24395 $this->SetCol($this->CurrCol);
24396 $this->y = $this->y0;
24397 $this->ChangeColumn = 1;
24398 // DIRECTIONALITY RTL
24399 if ($this->directionality == 'rtl') {
24400 $this->ChangeColumn = -($this->ChangeColumn);
24401 } // *OTL*
24402 // Stay on the page
24403 } else {
24404 // Go back to the first column
24405 // Page break
24406 if (count($this->columnbuffer)) {
24407 $this->printcolumnbuffer();
24408 }
24409 $this->AddPage($this->CurOrientation);
24410 $this->SetCol(0);
24411 $this->y0 = $this->tMargin;
24412 $this->ChangeColumn = -($this->NbCol - 1);
24413 // DIRECTIONALITY RTL
24414 if ($this->directionality == 'rtl') {
24415 $this->ChangeColumn = -($this->ChangeColumn);
24416 } // *OTL*
24417 }
24418 $this->x = $this->lMargin;
24419 } else {
24420 $this->AddPage($this->CurOrientation);
24421 }
24422 }
24423
24425 {
24426 // Columns ended (but page not ended) -> try to match all columns - unless disabled by using a custom column-break
24427 if (!$this->ColActive && $this->ColumnAdjust && !$this->keepColumns) {
24428 // Calculate adjustment to add to each column to calculate rel_y value
24429 $this->ColDetails[0]['add_y'] = 0;
24430 $last_col = 0;
24431 // Recursively add previous column's height
24432 for ($i = 1; $i < $this->NbCol; $i++) {
24433 if (isset($this->ColDetails[$i]['bottom_margin']) && $this->ColDetails[$i]['bottom_margin']) { // If any entries in the column
24434 $this->ColDetails[$i]['add_y'] = ($this->ColDetails[$i - 1]['bottom_margin'] - $this->y0) + $this->ColDetails[$i - 1]['add_y'];
24435 $last_col = $i; // Last column actually printed
24436 }
24437 }
24438
24439 // Calculate value for each position sensitive entry as though for one column
24440 foreach ($this->columnbuffer as $key => $s) {
24441 $t = $s['s'];
24442 if ($t == 'ACROFORM') {
24443 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24444 $this->columnbuffer[$key]['s'] = '';
24445 } elseif (preg_match('/BT \d+\.\d\d+ (\d+\.\d\d+) Td/', $t)) {
24446 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24447 } elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ [\-]{0,1}\d+\.\d\d+ re/', $t)) {
24448 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24449 } elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t)) {
24450 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24451 } elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t)) {
24452 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24453 } elseif (preg_match('/q \d+\.\d\d+ 0 0 \d+\.\d\d+ \d+\.\d\d+ (\d+\.\d\d+) cm \/(I|FO)\d+ Do Q/', $t)) {
24454 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24455 } elseif (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t)) {
24456 $this->columnbuffer[$key]['rel_y'] = $s['y'] + $this->ColDetails[$s['col']]['add_y'] - $this->y0;
24457 }
24458 }
24459 foreach ($this->internallink as $key => $f) {
24460 if (is_array($f) && isset($f['col'])) {
24461 $this->internallink[$key]['rel_y'] = $f['Y'] + $this->ColDetails[$f['col']]['add_y'] - $this->y0;
24462 }
24463 }
24464
24465 $breaks = [];
24466 foreach ($this->breakpoints as $c => $bpa) {
24467 foreach ($bpa as $rely) {
24468 $breaks[] = $rely + $this->ColDetails[$c]['add_y'] - $this->y0;
24469 }
24470 }
24471
24472
24473 if (isset($this->ColDetails[$last_col]['bottom_margin'])) {
24474 $lcbm = $this->ColDetails[$last_col]['bottom_margin'];
24475 } else {
24476 $lcbm = 0;
24477 }
24478 $sum_h = $this->ColDetails[$last_col]['add_y'] + $lcbm - $this->y0;
24479 // $sum_h = max($this->ColDetails[$last_col]['add_y'] + $this->ColDetails[$last_col]['bottom_margin'] - $this->y0, end($breaks));
24480 $target_h = ($sum_h / $this->NbCol);
24481
24482 $cbr = [];
24483 for ($i = 1; $i < $this->NbCol; $i++) {
24484 $th = ($sum_h * $i / $this->NbCol);
24485 foreach ($breaks as $bk => $val) {
24486 if ($val > $th) {
24487 if (($val - $th) < ($th - $breaks[$bk - 1])) {
24488 $cbr[$i - 1] = $val;
24489 } else {
24490 $cbr[$i - 1] = $breaks[$bk - 1];
24491 }
24492 break;
24493 }
24494 }
24495 }
24496 $cbr[($this->NbCol - 1)] = $sum_h;
24497
24498 // mPDF 6
24499 // Avoid outputing with 1st column empty
24500 if (isset($cbr[0]) && $cbr[0] == 0) {
24501 for ($i = 0; $i < $this->NbCol - 1; $i++) {
24502 $cbr[$i] = $cbr[$i + 1];
24503 }
24504 }
24505
24506 // Now update the columns - divide into columns of approximately equal value
24507 $last_new_col = 0;
24508 $yadj = 0; // mm
24509 $xadj = 0;
24510 $last_col_bottom = 0;
24511 $lowest_bottom_y = 0;
24512 $block_bottom = 0;
24513 $newcolumn = 0;
24514 foreach ($this->columnbuffer as $key => $s) {
24515 if (isset($s['rel_y'])) { // only process position sensitive data
24516 if ($s['rel_y'] >= $cbr[$newcolumn]) {
24517 $newcolumn++;
24518 } else {
24519 $newcolumn = $last_new_col;
24520 }
24521
24522
24523 $block_bottom = max($block_bottom, ($s['rel_y'] + $s['h']));
24524
24525 if ($this->directionality == 'rtl') { // *OTL*
24526 $xadj = -(($newcolumn - $s['col']) * ($this->ColWidth + $this->ColGap)); // *OTL*
24527 } // *OTL*
24528 else { // *OTL*
24529 $xadj = ($newcolumn - $s['col']) * ($this->ColWidth + $this->ColGap);
24530 } // *OTL*
24531
24532 if ($last_new_col != $newcolumn) { // Added new column
24533 $last_col_bottom = $this->columnbuffer[$key]['rel_y'];
24534 $block_bottom = 0;
24535 }
24536 $yadj = ($s['rel_y'] - $s['y']) - ($last_col_bottom) + $this->y0;
24537 // callback function
24538 $t = $s['s'];
24539
24540 // mPDF 5.7+
24541 $t = $this->columnAdjustPregReplace('Td', $xadj, $yadj, '/BT (\d+\.\d\d+) (\d+\.\d\d+) Td/', $t);
24542 $t = $this->columnAdjustPregReplace('re', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) ([\-]{0,1}\d+\.\d\d+) re/', $t);
24543 $t = $this->columnAdjustPregReplace('l', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) l/', $t);
24544 $t = $this->columnAdjustPregReplace('img', $xadj, $yadj, '/q (\d+\.\d\d+) 0 0 (\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) cm \/(I|FO)/', $t);
24545 $t = $this->columnAdjustPregReplace('draw', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) m/', $t);
24546 $t = $this->columnAdjustPregReplace('bezier', $xadj, $yadj, '/(\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) (\d+\.\d\d+) c/', $t);
24547
24548 $this->columnbuffer[$key]['s'] = $t;
24549 $this->columnbuffer[$key]['newcol'] = $newcolumn;
24550 $this->columnbuffer[$key]['newy'] = $s['y'] + $yadj;
24551 $last_new_col = $newcolumn;
24552 $clb = $s['y'] + $yadj + $s['h']; // bottom_margin of current
24553 if ((isset($this->ColDetails[$newcolumn]['max_bottom']) && $clb > $this->ColDetails[$newcolumn]['max_bottom']) || (!isset($this->ColDetails[$newcolumn]['max_bottom']) && $clb)) {
24554 $this->ColDetails[$newcolumn]['max_bottom'] = $clb;
24555 }
24556 if ($clb > $lowest_bottom_y) {
24557 $lowest_bottom_y = $clb;
24558 }
24559 // Adjust LINKS
24560 if (isset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])])) {
24561 $ref = $this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])];
24562 $this->PageLinks[$this->page][$ref][0] += ($xadj * Mpdf::SCALE);
24563 $this->PageLinks[$this->page][$ref][1] -= ($yadj * Mpdf::SCALE);
24564 unset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])]);
24565 }
24566 // Adjust FORM FIELDS
24567 if (isset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])])) {
24568 $ref = $this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])];
24569 $this->form->forms[$ref]['x'] += ($xadj);
24570 $this->form->forms[$ref]['y'] += ($yadj);
24571 unset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])]);
24572 }
24573 /* -- ANNOTATIONS -- */
24574 if (isset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])])) {
24575 $ref = $this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])];
24576 if ($this->PageAnnots[$this->page][$ref]['x'] < 0) {
24577 $this->PageAnnots[$this->page][$ref]['x'] -= ($xadj);
24578 } else {
24579 $this->PageAnnots[$this->page][$ref]['x'] += ($xadj);
24580 }
24581 $this->PageAnnots[$this->page][$ref]['y'] += ($yadj); // unlike PageLinks, Page annots has y values from top in mm
24582 unset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])]);
24583 }
24584 /* -- END ANNOTATIONS -- */
24585 }
24586 }
24587
24588 /* -- BOOKMARKS -- */
24589 // Adjust Bookmarks
24590 foreach ($this->col_BMoutlines as $v) {
24591 $this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $this->y0, 'p' => $v['p']];
24592 }
24593 /* -- END BOOKMARKS -- */
24594
24595 /* -- TOC -- */
24596
24597 // Adjust ToC
24598 foreach ($this->col_toc as $v) {
24599 $this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
24600 $this->links[$v['link']][1] = $this->y0;
24601 }
24602 /* -- END TOC -- */
24603
24604 // Adjust column length to be equal
24605 if ($this->colvAlign == 'J') {
24606 foreach ($this->columnbuffer as $key => $s) {
24607 if (isset($s['rel_y'])) { // only process position sensitive data
24608 // Set ratio to expand y values or heights
24609 if (isset($this->ColDetails[$s['newcol']]['max_bottom']) && $this->ColDetails[$s['newcol']]['max_bottom'] && $this->ColDetails[$s['newcol']]['max_bottom'] != $this->y0) {
24610 $ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['newcol']]['max_bottom'] - ($this->y0));
24611 } else {
24612 $ratio = 1;
24613 }
24614 if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
24615 $yadj = ($s['newy'] - $this->y0) * ($ratio - 1);
24616
24617 // Adjust LINKS
24618 if (isset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])])) {
24619 $ref = $this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])];
24620 $this->PageLinks[$this->page][$ref][1] -= ($yadj * Mpdf::SCALE); // y value
24621 $this->PageLinks[$this->page][$ref][3] *= $ratio; // height
24622 unset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])]);
24623 }
24624 // Adjust FORM FIELDS
24625 if (isset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])])) {
24626 $ref = $this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])];
24627 $this->form->forms[$ref]['x'] += ($xadj);
24628 $this->form->forms[$ref]['y'] += ($yadj);
24629 unset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])]);
24630 }
24631 /* -- ANNOTATIONS -- */
24632 if (isset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])])) {
24633 $ref = $this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])];
24634 $this->PageAnnots[$this->page][$ref]['y'] += ($yadj);
24635 unset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])]);
24636 }
24637 /* -- END ANNOTATIONS -- */
24638 }
24639 }
24640 }
24641 foreach ($this->internallink as $key => $f) {
24642 if (is_array($f) && isset($f['col'])) {
24643 $last_col_bottom = 0;
24644 for ($nbc = 0; $nbc < $this->NbCol; $nbc++) {
24645 if ($f['rel_y'] >= $cbr[$nbc]) {
24646 $last_col_bottom = $cbr[$nbc];
24647 }
24648 }
24649 $yadj = ($f['rel_y'] - $f['Y']) - $last_col_bottom + $this->y0;
24650 $f['Y'] += $yadj;
24651 unset($f['col']);
24652 unset($f['rel_y']);
24653 $this->internallink[$key] = $f;
24654 }
24655 }
24656
24657 $last_col = -1;
24658 $trans_on = false;
24659 foreach ($this->columnbuffer as $key => $s) {
24660 if (isset($s['rel_y'])) { // only process position sensitive data
24661 // Set ratio to expand y values or heights
24662 if (isset($this->ColDetails[$s['newcol']]['max_bottom']) && $this->ColDetails[$s['newcol']]['max_bottom'] && $this->ColDetails[$s['newcol']]['max_bottom'] != $this->y0) {
24663 $ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['newcol']]['max_bottom'] - ($this->y0));
24664 } else {
24665 $ratio = 1;
24666 }
24667 if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
24668 // Start Transformation
24669 $this->pages[$this->page] .= $this->StartTransform(true) . "\n";
24670 $this->pages[$this->page] .= $this->transformScale(100, $ratio * 100, $x = '', $this->y0, true) . "\n";
24671 $trans_on = true;
24672 }
24673 }
24674 // Now output the adjusted values
24675 $this->pages[$this->page] .= $s['s'] . "\n";
24676 if (isset($s['rel_y']) && ($ratio > 1) && ($ratio <= $this->max_colH_correction)) { // only process position sensitive data
24677 // Stop Transformation
24678 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
24679 $trans_on = false;
24680 }
24681 }
24682 if ($trans_on) {
24683 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
24684 }
24685 } else { // if NOT $this->colvAlign == 'J'
24686 // Now output the adjusted values
24687 foreach ($this->columnbuffer as $s) {
24688 $this->pages[$this->page] .= $s['s'] . "\n";
24689 }
24690 }
24691 if ($lowest_bottom_y > 0) {
24692 $this->y = $lowest_bottom_y;
24693 }
24694 } // Columns not ended but new page -> align columns (can leave the columns alone - just tidy up the height)
24695 elseif ($this->colvAlign == 'J' && $this->ColumnAdjust && !$this->keepColumns) {
24696 // calculate the lowest bottom margin
24697 $lowest_bottom_y = 0;
24698 foreach ($this->columnbuffer as $key => $s) {
24699 // Only process output data
24700 $t = $s['s'];
24701 if ($t == 'ACROFORM' || (preg_match('/BT \d+\.\d\d+ (\d+\.\d\d+) Td/', $t)) || (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ [\-]{0,1}\d+\.\d\d+ re/', $t)) ||
24702 (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t)) ||
24703 (preg_match('/q \d+\.\d\d+ 0 0 \d+\.\d\d+ \d+\.\d\d+ (\d+\.\d\d+) cm \/(I|FO)\d+ Do Q/', $t)) ||
24704 (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t)) ||
24705 (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t))) {
24706 $clb = $s['y'] + $s['h'];
24707 if ((isset($this->ColDetails[$s['col']]['max_bottom']) && $clb > $this->ColDetails[$s['col']]['max_bottom']) || !isset($this->ColDetails[$s['col']]['max_bottom'])) {
24708 $this->ColDetails[$s['col']]['max_bottom'] = $clb;
24709 }
24710 if ($clb > $lowest_bottom_y) {
24711 $lowest_bottom_y = $clb;
24712 }
24713 $this->columnbuffer[$key]['rel_y'] = $s['y']; // Marks position sensitive data to process later
24714 if ($t == 'ACROFORM') {
24715 $this->columnbuffer[$key]['s'] = '';
24716 }
24717 }
24718 }
24719 // Adjust column length equal
24720 foreach ($this->columnbuffer as $key => $s) {
24721 // Set ratio to expand y values or heights
24722 if (isset($this->ColDetails[$s['col']]['max_bottom']) && $this->ColDetails[$s['col']]['max_bottom']) {
24723 $ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['col']]['max_bottom'] - ($this->y0));
24724 } else {
24725 $ratio = 1;
24726 }
24727 if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
24728 $yadj = ($s['y'] - $this->y0) * ($ratio - 1);
24729
24730 // Adjust LINKS
24731 if (isset($s['rel_y'])) { // only process position sensitive data
24732 // otherwise triggers for all entries in column buffer (.e.g. formatting) and makes below adjustments more than once
24733 if (isset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])])) {
24734 $ref = $this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])];
24735 $this->PageLinks[$this->page][$ref][1] -= ($yadj * Mpdf::SCALE); // y value
24736 $this->PageLinks[$this->page][$ref][3] *= $ratio; // height
24737 unset($this->columnLinks[$s['col']][intval($s['x'])][intval($s['y'])]);
24738 }
24739 // Adjust FORM FIELDS
24740 if (isset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])])) {
24741 $ref = $this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])];
24742 $this->form->forms[$ref]['x'] += ($xadj);
24743 $this->form->forms[$ref]['y'] += ($yadj);
24744 unset($this->columnForms[$s['col']][intval($s['x'])][intval($s['y'])]);
24745 }
24746 /* -- ANNOTATIONS -- */
24747 if (isset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])])) {
24748 $ref = $this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])];
24749 $this->PageAnnots[$this->page][$ref]['y'] += ($yadj);
24750 unset($this->columnAnnots[$s['col']][intval($s['x'])][intval($s['y'])]);
24751 }
24752 /* -- END ANNOTATIONS -- */
24753 }
24754 }
24755 }
24756
24757 /* -- BOOKMARKS -- */
24758
24759 // Adjust Bookmarks
24760 foreach ($this->col_BMoutlines as $v) {
24761 $this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $this->y0, 'p' => $v['p']];
24762 }
24763 /* -- END BOOKMARKS -- */
24764
24765 /* -- TOC -- */
24766
24767 // Adjust ToC
24768 foreach ($this->col_toc as $v) {
24769 $this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
24770 $this->links[$v['link']][1] = $this->y0;
24771 }
24772 /* -- END TOC -- */
24773
24774 $trans_on = false;
24775 foreach ($this->columnbuffer as $key => $s) {
24776
24777 if (isset($s['rel_y'])) { // only process position sensitive data
24778
24779 // Set ratio to expand y values or heights
24780 if (isset($this->ColDetails[$s['col']]['max_bottom']) && $this->ColDetails[$s['col']]['max_bottom']) {
24781 $ratio = ($lowest_bottom_y - ($this->y0)) / ($this->ColDetails[$s['col']]['max_bottom'] - ($this->y0));
24782 } else {
24783 $ratio = 1;
24784 }
24785
24786 if (($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
24787 // Start Transformation
24788 $this->pages[$this->page] .= $this->StartTransform(true) . "\n";
24789 $this->pages[$this->page] .= $this->transformScale(100, $ratio * 100, $x = '', $this->y0, true) . "\n";
24790 $trans_on = true;
24791 }
24792 }
24793
24794 // Now output the adjusted values
24795 $this->pages[$this->page] .= $s['s'] . "\n";
24796 if (isset($s['rel_y']) && ($ratio > 1) && ($ratio <= $this->max_colH_correction)) {
24797 // Stop Transformation
24798 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
24799 $trans_on = false;
24800 }
24801 }
24802
24803 if ($trans_on) {
24804 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
24805 }
24806
24807 if ($lowest_bottom_y > 0) {
24808 $this->y = $lowest_bottom_y;
24809 }
24810
24811 } else { // Just reproduce the page as it was
24812
24813 // If page has not ended but height adjustment was disabled by custom column-break - adjust y
24814 $lowest_bottom_y = 0;
24815
24816 if (!$this->ColActive && (!$this->ColumnAdjust || $this->keepColumns)) {
24817
24818 // calculate the lowest bottom margin
24819 foreach ($this->columnbuffer as $key => $s) {
24820
24821 // Only process output data
24822 $t = $s['s'];
24823 if ($t === 'ACROFORM'
24824 || (preg_match('/BT \d+\.\d\d+ (\d+\.\d\d+) Td/', $t))
24825 || (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ [\-]{0,1}\d+\.\d\d+ re/', $t))
24826 || (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) l/', $t))
24827 || (preg_match('/q \d+\.\d\d+ 0 0 \d+\.\d\d+ \d+\.\d\d+ (\d+\.\d\d+) cm \/(I|FO)\d+ Do Q/', $t))
24828 || (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) m/', $t))
24829 || (preg_match('/\d+\.\d\d+ (\d+\.\d\d+) \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ \d+\.\d\d+ c/', $t))) {
24830
24831 $clb = $s['y'] + $s['h'];
24832
24833 if (isset($this->ColDetails[$s['col']]['max_bottom']) && $clb > $this->ColDetails[$s['col']]['max_bottom'] || (!isset($this->ColDetails[$s['col']]['max_bottom']) && $clb)) {
24834 $this->ColDetails[$s['col']]['max_bottom'] = $clb;
24835 }
24836
24837 if ($clb > $lowest_bottom_y) {
24838 $lowest_bottom_y = $clb;
24839 }
24840 }
24841 }
24842 }
24843
24844 foreach ($this->columnbuffer as $key => $s) {
24845 if ($s['s'] != 'ACROFORM') {
24846 $this->pages[$this->page] .= $s['s'] . "\n";
24847 }
24848 }
24849
24850 if ($lowest_bottom_y > 0) {
24851 $this->y = $lowest_bottom_y;
24852 }
24853
24854 /* -- BOOKMARKS -- */
24855 // Output Bookmarks
24856 foreach ($this->col_BMoutlines as $v) {
24857 $this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']];
24858 }
24859 /* -- END BOOKMARKS -- */
24860
24861 /* -- TOC -- */
24862 // Output ToC
24863 foreach ($this->col_toc as $v) {
24864 $this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
24865 }
24866 /* -- END TOC -- */
24867 }
24868
24869 foreach ($this->internallink as $key => $f) {
24870
24871 if (isset($this->internallink[$key]['col'])) {
24872 unset($this->internallink[$key]['col']);
24873 }
24874
24875 if (isset($this->internallink[$key]['rel_y'])) {
24876 unset($this->internallink[$key]['rel_y']);
24877 }
24878 }
24879
24880 $this->columnbuffer = [];
24881 $this->ColDetails = [];
24882 $this->columnLinks = [];
24883 $this->columnAnnots = [];
24884 $this->columnForms = [];
24885
24886 $this->col_BMoutlines = [];
24887 $this->col_toc = [];
24888 $this->breakpoints = [];
24889 }
24890
24891 // mPDF 5.7+
24892 function columnAdjustPregReplace($type, $xadj, $yadj, $pattern, $subject)
24893 {
24894 preg_match($pattern, $subject, $matches);
24895
24896 if (!count($matches)) {
24897 return $subject;
24898 }
24899
24900 if (!isset($matches[3])) {
24901 $matches[3] = 0;
24902 }
24903
24904 if (!isset($matches[4])) {
24905 $matches[4] = 0;
24906 }
24907
24908 if (!isset($matches[5])) {
24909 $matches[5] = 0;
24910 }
24911
24912 if (!isset($matches[6])) {
24913 $matches[6] = 0;
24914 }
24915
24916 return str_replace($matches[0], $this->columnAdjustAdd($type, Mpdf::SCALE, $xadj, $yadj, $matches[1], $matches[2], $matches[3], $matches[4], $matches[5], $matches[6]), $subject);
24917 }
24918 /* -- END COLUMNS -- */
24919
24920 // ==================================================================
24921 /* -- TABLES -- */
24923 {
24924 if (count($this->cellBorderBuffer)) {
24925
24926 sort($this->cellBorderBuffer);
24927
24928 foreach ($this->cellBorderBuffer as $cbb) {
24929
24930 $cba = unpack("A16dom/nbord/A1side/ns/dbw/a6ca/A10style/dx/dy/dw/dh/dmbl/dmbr/dmrt/dmrb/dmtl/dmtr/dmlt/dmlb/dcpd/dover/", $cbb);
24931 $side = $cba['side'];
24932 $color = str_pad($cba['ca'], 6, "\x00");
24933
24934 $details = [];
24935
24936 $details[$side]['dom'] = (float) $cba['dom'];
24937 $details[$side]['s'] = $cba['s'];
24938 $details[$side]['w'] = $cba['bw'];
24939 $details[$side]['c'] = $color;
24940 $details[$side]['style'] = trim($cba['style']);
24941
24942 $details['mbw']['BL'] = $cba['mbl'];
24943 $details['mbw']['BR'] = $cba['mbr'];
24944 $details['mbw']['RT'] = $cba['mrt'];
24945 $details['mbw']['RB'] = $cba['mrb'];
24946 $details['mbw']['TL'] = $cba['mtl'];
24947 $details['mbw']['TR'] = $cba['mtr'];
24948 $details['mbw']['LT'] = $cba['mlt'];
24949 $details['mbw']['LB'] = $cba['mlb'];
24950
24951 $details['cellposdom'] = $cba['cpd'];
24952
24953 $details['p'] = $side;
24954
24955 if ($cba['over'] == 1) {
24956 $details[$side]['overlay'] = true;
24957 } else {
24958 $details[$side]['overlay'] = false;
24959 }
24960
24961 $this->_tableRect($cba['x'], $cba['y'], $cba['w'], $cba['h'], $cba['bord'], $details, false, false);
24962 }
24963
24964 $this->cellBorderBuffer = [];
24965 }
24966 }
24967
24968 // ==================================================================
24970 {
24971
24972 if (!$this->table_rotate) {
24973
24974 $this->pages[$this->page] .= $this->tablebuffer;
24975
24976 foreach ($this->tbrot_Links as $p => $l) {
24977 foreach ($l as $v) {
24978 $this->PageLinks[$p][] = $v;
24979 }
24980 }
24981 $this->tbrot_Links = [];
24982
24983 /* -- ANNOTATIONS -- */
24984 foreach ($this->tbrot_Annots as $p => $l) {
24985 foreach ($l as $v) {
24986 $this->PageAnnots[$p][] = $v;
24987 }
24988 }
24989 $this->tbrot_Annots = [];
24990 /* -- END ANNOTATIONS -- */
24991
24992 /* -- BOOKMARKS -- */
24993 // Output Bookmarks
24994 foreach ($this->tbrot_BMoutlines as $v) {
24995 $this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']];
24996 }
24997 $this->tbrot_BMoutlines = [];
24998 /* -- END BOOKMARKS -- */
24999
25000 /* -- TOC -- */
25001 // Output ToC
25002 foreach ($this->tbrot_toc as $v) {
25003 $this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
25004 }
25005 $this->tbrot_toc = [];
25006 /* -- END TOC -- */
25007
25008 return;
25009 }
25010
25011 // elseif rotated
25012 $lm = $this->lMargin + $this->blk[$this->blklvl]['outer_left_margin'] + $this->blk[$this->blklvl]['border_left']['w'] + $this->blk[$this->blklvl]['padding_left'];
25013 $pw = $this->blk[$this->blklvl]['inner_width'];
25014
25015 // Start Transformation
25016 $this->pages[$this->page] .= $this->StartTransform(true) . "\n";
25017
25018 if ($this->table_rotate > 1) { // clockwise
25019
25020 if ($this->tbrot_align == 'L') {
25021 $xadj = $this->tbrot_h; // align L (as is)
25022 } elseif ($this->tbrot_align == 'R') {
25023 $xadj = $lm - $this->tbrot_x0 + ($pw); // align R
25024 } else {
25025 $xadj = $lm - $this->tbrot_x0 + (($pw + $this->tbrot_h) / 2); // align C
25026 }
25027
25028 $yadj = 0;
25029
25030 } else { // anti-clockwise
25031
25032 if ($this->tbrot_align == 'L') {
25033 $xadj = 0; // align L (as is)
25034 } elseif ($this->tbrot_align == 'R') {
25035 $xadj = $lm - $this->tbrot_x0 + ($pw - $this->tbrot_h); // align R
25036 } else {
25037 $xadj = $lm - $this->tbrot_x0 + (($pw - $this->tbrot_h) / 2); // align C
25038 }
25039
25040 $yadj = $this->tbrot_w;
25041 }
25042
25043
25044 $this->pages[$this->page] .= $this->transformTranslate($xadj, $yadj, true) . "\n";
25045 $this->pages[$this->page] .= $this->transformRotate($this->table_rotate, $this->tbrot_x0, $this->tbrot_y0, true) . "\n";
25046
25047 // Now output the adjusted values
25048 $this->pages[$this->page] .= $this->tablebuffer;
25049
25050 foreach ($this->tbrot_Links as $p => $l) {
25051
25052 foreach ($l as $v) {
25053
25054 $w = $v[2] / Mpdf::SCALE;
25055 $h = $v[3] / Mpdf::SCALE;
25056 $ax = ($v[0] / Mpdf::SCALE) - $this->tbrot_x0;
25057 $ay = (($this->hPt - $v[1]) / Mpdf::SCALE) - $this->tbrot_y0;
25058
25059 if ($this->table_rotate > 1) { // clockwise
25060 $bx = $this->tbrot_x0 + $xadj - $ay - $h;
25061 $by = $this->tbrot_y0 + $yadj + $ax;
25062 } else {
25063 $bx = $this->tbrot_x0 + $xadj + $ay;
25064 $by = $this->tbrot_y0 + $yadj - $ax - $w;
25065 }
25066
25067 $v[0] = $bx * Mpdf::SCALE;
25068 $v[1] = ($this->h - $by) * Mpdf::SCALE;
25069 $v[2] = $h * Mpdf::SCALE; // swap width and height
25070 $v[3] = $w * Mpdf::SCALE;
25071
25072 $this->PageLinks[$p][] = $v;
25073 }
25074 }
25075
25076 $this->tbrot_Links = [];
25077 foreach ($this->internallink as $key => $f) {
25078 if (is_array($f) && isset($f['tbrot'])) {
25079 $f['Y'] = $this->tbrot_y0;
25080 $f['PAGE'] = $this->page;
25081 unset($f['tbrot']);
25082 $this->internallink[$key] = $f;
25083 }
25084 }
25085
25086 /* -- ANNOTATIONS -- */
25087 foreach ($this->tbrot_Annots as $p => $l) {
25088 foreach ($l as $v) {
25089 $ax = abs($v['x']) - $this->tbrot_x0; // abs because -ve values are internally set and held for reference if annotMargin set
25090 $ay = $v['y'] - $this->tbrot_y0;
25091
25092 if ($this->table_rotate > 1) { // clockwise
25093 $bx = $this->tbrot_x0 + $xadj - $ay;
25094 $by = $this->tbrot_y0 + $yadj + $ax;
25095 } else {
25096 $bx = $this->tbrot_x0 + $xadj + $ay;
25097 $by = $this->tbrot_y0 + $yadj - $ax;
25098 }
25099
25100 if ($v['x'] < 0) {
25101 $v['x'] = -$bx;
25102 } else {
25103 $v['x'] = $bx;
25104 }
25105
25106 $v['y'] = ($by);
25107 $this->PageAnnots[$p][] = $v;
25108 }
25109 }
25110
25111 $this->tbrot_Annots = [];
25112 /* -- END ANNOTATIONS -- */
25113
25114 /* -- BOOKMARKS -- */
25115 // Adjust Bookmarks
25116 foreach ($this->tbrot_BMoutlines as $v) {
25117 $v['y'] = $this->tbrot_y0;
25118 $this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $this->page];
25119 }
25120 /* -- END BOOKMARKS -- */
25121
25122 /* -- TOC -- */
25123 // Adjust ToC - uses document page number
25124 foreach ($this->tbrot_toc as $v) {
25125 $this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $this->page, 'link' => $v['link'], 'toc_id' => $v['toc_id']];
25126 $this->links[$v['link']][1] = $this->tbrot_y0;
25127 }
25128 /* -- END TOC -- */
25129
25130 $this->tbrot_BMoutlines = [];
25131 $this->tbrot_toc = [];
25132
25133 // Stop Transformation
25134 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
25135
25136 $this->y = $this->tbrot_y0 + $this->tbrot_w;
25137 $this->x = $this->lMargin;
25138
25139 $this->tablebuffer = '';
25140 }
25141
25146 {
25147 if (!$this->kwt_moved) {
25148
25149 foreach ($this->kwt_buffer as $s) {
25150 $this->pages[$this->page] .= $s['s'] . "\n";
25151 }
25152
25153 foreach ($this->kwt_Links as $p => $l) {
25154 foreach ($l as $v) {
25155 $this->PageLinks[$p][] = $v;
25156 }
25157 }
25158
25159 $this->kwt_Links = [];
25160
25161 /* -- ANNOTATIONS -- */
25162 foreach ($this->kwt_Annots as $p => $l) {
25163 foreach ($l as $v) {
25164 $this->PageAnnots[$p][] = $v;
25165 }
25166 }
25167 $this->kwt_Annots = [];
25168 /* -- END ANNOTATIONS -- */
25169
25170 /* -- INDEX -- */
25171 // Output Reference (index)
25172 foreach ($this->kwt_Reference as $v) {
25173
25174 $Present = 0;
25175
25176 for ($i = 0; $i < count($this->Reference); $i++) {
25177 if ($this->Reference[$i]['t'] == $v['t']) {
25178 $Present = 1;
25179 if (!in_array($v['op'], $this->Reference[$i]['p'])) {
25180 $this->Reference[$i]['p'][] = $v['op'];
25181 }
25182 }
25183 }
25184
25185 if ($Present == 0) {
25186 $this->Reference[] = ['t' => $v['t'], 'p' => [$v['op']]];
25187 }
25188 }
25189 $this->kwt_Reference = [];
25190 /* -- END INDEX -- */
25191
25192 /* -- BOOKMARKS -- */
25193 // Output Bookmarks
25194 foreach ($this->kwt_BMoutlines as $v) {
25195 $this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $v['p']];
25196 }
25197 $this->kwt_BMoutlines = [];
25198 /* -- END BOOKMARKS -- */
25199
25200 /* -- TOC -- */
25201 // Output ToC
25202 foreach ($this->kwt_toc as $v) {
25203 $this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $v['p'], 'link' => $v['link'], 'toc_id' => $v['toc_id']];
25204 }
25205 $this->kwt_toc = [];
25206 /* -- END TOC -- */
25207
25208 $this->pageoutput[$this->page] = []; // mPDF 6
25209
25210 return;
25211 }
25212
25213 // Start Transformation
25214 $this->pages[$this->page] .= $this->StartTransform(true) . "\n";
25215 $xadj = $this->lMargin - $this->kwt_x0;
25216 // $yadj = $this->y - $this->kwt_y0 ;
25217 $yadj = $this->tMargin - $this->kwt_y0;
25218
25219 $this->pages[$this->page] .= $this->transformTranslate($xadj, $yadj, true) . "\n";
25220
25221 // Now output the adjusted values
25222 foreach ($this->kwt_buffer as $s) {
25223 $this->pages[$this->page] .= $s['s'] . "\n";
25224 }
25225
25226 // Adjust hyperLinks
25227 foreach ($this->kwt_Links as $p => $l) {
25228 foreach ($l as $v) {
25229 $bx = $this->kwt_x0 + $xadj;
25230 $by = $this->kwt_y0 + $yadj;
25231 $v[0] = $bx * Mpdf::SCALE;
25232 $v[1] = ($this->h - $by) * Mpdf::SCALE;
25233 $this->PageLinks[$p][] = $v;
25234 }
25235 }
25236
25237 foreach ($this->internallink as $key => $f) {
25238 if (is_array($f) && isset($f['kwt'])) {
25239 $f['Y'] += $yadj;
25240 $f['PAGE'] = $this->page;
25241 unset($f['kwt']);
25242 $this->internallink[$key] = $f;
25243 }
25244 }
25245
25246 /* -- ANNOTATIONS -- */
25247 foreach ($this->kwt_Annots as $p => $l) {
25248 foreach ($l as $v) {
25249 $bx = $this->kwt_x0 + $xadj;
25250 $by = $this->kwt_y0 + $yadj;
25251 if ($v['x'] < 0) {
25252 $v['x'] = -$bx;
25253 } else {
25254 $v['x'] = $bx;
25255 }
25256 $v['y'] = $by;
25257 $this->PageAnnots[$p][] = $v;
25258 }
25259 }
25260 /* -- END ANNOTATIONS -- */
25261
25262 /* -- BOOKMARKS -- */
25263
25264 // Adjust Bookmarks
25265 foreach ($this->kwt_BMoutlines as $v) {
25266 if ($v['y'] != 0) {
25267 $v['y'] += $yadj;
25268 }
25269 $this->BMoutlines[] = ['t' => $v['t'], 'l' => $v['l'], 'y' => $v['y'], 'p' => $this->page];
25270 }
25271 /* -- END BOOKMARKS -- */
25272
25273 /* -- INDEX -- */
25274 // Adjust Reference (index)
25275 foreach ($this->kwt_Reference as $v) {
25276
25277 $Present = 0;
25278
25279 // Search the reference (AND Ref/PageNo) in the array
25280 for ($i = 0; $i < count($this->Reference); $i++) {
25281 if ($this->Reference[$i]['t'] == $v['t']) {
25282 $Present = 1;
25283 if (!in_array($this->page, $this->Reference[$i]['p'])) {
25284 $this->Reference[$i]['p'][] = $this->page;
25285 }
25286 }
25287 }
25288
25289 if ($Present == 0) {
25290 $this->Reference[] = ['t' => $v['t'], 'p' => [$this->page]];
25291 }
25292 }
25293 /* -- END INDEX -- */
25294
25295 /* -- TOC -- */
25296
25297 // Adjust ToC
25298 foreach ($this->kwt_toc as $v) {
25299 $this->tableOfContents->_toc[] = ['t' => $v['t'], 'l' => $v['l'], 'p' => $this->page, 'link' => $v['link'], 'toc_id' => $v['toc_id']];
25300 $this->links[$v['link']][0] = $this->page;
25301 $this->links[$v['link']][1] += $yadj;
25302 }
25303 /* -- END TOC -- */
25304
25305
25306 $this->kwt_Links = [];
25307 $this->kwt_Annots = [];
25308
25309 $this->kwt_Reference = [];
25310 $this->kwt_BMoutlines = [];
25311 $this->kwt_toc = [];
25312
25313 // Stop Transformation
25314 $this->pages[$this->page] .= $this->StopTransform(true) . "\n";
25315
25316 $this->kwt_buffer = [];
25317
25318 $this->y += $this->kwt_height;
25319 $this->pageoutput[$this->page] = []; // mPDF 6
25320 }
25321 /* -- END TABLES -- */
25322
25324 {
25325 if (count($this->floatbuffer)) {
25326 $this->objectbuffer = $this->floatbuffer;
25327 $this->printobjectbuffer(false);
25328 $this->objectbuffer = [];
25329 $this->floatbuffer = [];
25330 $this->floatmargins = [];
25331 }
25332 }
25333
25334 function Circle($x, $y, $r, $style = 'S')
25335 {
25336 $this->Ellipse($x, $y, $r, $r, $style);
25337 }
25338
25339 function Ellipse($x, $y, $rx, $ry, $style = 'S')
25340 {
25341 if ($style === 'F') {
25342 $op = 'f';
25343 } elseif ($style === 'FD' or $style === 'DF') {
25344 $op = 'B';
25345 } else {
25346 $op = 'S';
25347 }
25348
25349 $lx = 4 / 3 * (M_SQRT2 - 1) * $rx;
25350 $ly = 4 / 3 * (M_SQRT2 - 1) * $ry;
25351
25352 $h = $this->h;
25353
25354 $this->writer->write(sprintf('%.3F %.3F m %.3F %.3F %.3F %.3F %.3F %.3F c', ($x + $rx) * Mpdf::SCALE, ($h - $y) * Mpdf::SCALE, ($x + $rx) * Mpdf::SCALE, ($h - ($y - $ly)) * Mpdf::SCALE, ($x + $lx) * Mpdf::SCALE, ($h - ($y - $ry)) * Mpdf::SCALE, $x * Mpdf::SCALE, ($h - ($y - $ry)) * Mpdf::SCALE));
25355 $this->writer->write(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c', ($x - $lx) * Mpdf::SCALE, ($h - ($y - $ry)) * Mpdf::SCALE, ($x - $rx) * Mpdf::SCALE, ($h - ($y - $ly)) * Mpdf::SCALE, ($x - $rx) * Mpdf::SCALE, ($h - $y) * Mpdf::SCALE));
25356 $this->writer->write(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c', ($x - $rx) * Mpdf::SCALE, ($h - ($y + $ly)) * Mpdf::SCALE, ($x - $lx) * Mpdf::SCALE, ($h - ($y + $ry)) * Mpdf::SCALE, $x * Mpdf::SCALE, ($h - ($y + $ry)) * Mpdf::SCALE));
25357 $this->writer->write(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F c %s', ($x + $lx) * Mpdf::SCALE, ($h - ($y + $ry)) * Mpdf::SCALE, ($x + $rx) * Mpdf::SCALE, ($h - ($y + $ly)) * Mpdf::SCALE, ($x + $rx) * Mpdf::SCALE, ($h - $y) * Mpdf::SCALE, $op));
25358 }
25359
25360 /* -- DIRECTW -- */
25361 function AutosizeText($text, $w, $font, $style, $szfont = 72)
25362 {
25363
25364 $text = ' ' . $text . ' ';
25365
25366 $this->SetFont($font, $style, $szfont, false);
25367
25368 $text = $this->purify_utf8_text($text);
25369 if ($this->text_input_as_HTML) {
25370 $text = $this->all_entities_to_utf8($text);
25371 }
25372 if ($this->usingCoreFont) {
25373 $text = mb_convert_encoding($text, $this->mb_enc, 'UTF-8');
25374 }
25375
25376 // DIRECTIONALITY
25377 if (preg_match("/([" . $this->pregRTLchars . "])/u", $text)) {
25378 $this->biDirectional = true;
25379 }
25380
25381 $textvar = 0;
25382 $save_OTLtags = $this->OTLtags;
25383 $this->OTLtags = [];
25384
25385 if ($this->useKerning) {
25386 if ($this->CurrentFont['haskernGPOS']) {
25387 $this->OTLtags['Plus'] .= ' kern';
25388 } else {
25389 $textvar = ($textvar | TextVars::FC_KERNING);
25390 }
25391 }
25392
25393 /* -- OTL -- */
25394 // Use OTL OpenType Table Layout - GSUB & GPOS
25395 if (isset($this->CurrentFont['useOTL']) && $this->CurrentFont['useOTL']) {
25396 $text = $this->otl->applyOTL($text, $this->CurrentFont['useOTL']);
25397 $OTLdata = $this->otl->OTLdata;
25398 }
25399 /* -- END OTL -- */
25400
25401 $this->OTLtags = $save_OTLtags;
25402
25403 $this->magic_reverse_dir($text, $this->directionality, $OTLdata);
25404
25405 $width = $this->sizeConverter->convert($w);
25406 $loop = 0;
25407
25408 while ($loop == 0) {
25409
25410 $this->SetFont($font, $style, $szfont, false);
25411 $sz = $this->GetStringWidth($text, true, $OTLdata, $textvar);
25412
25413 if ($sz > $w) {
25414 $szfont --;
25415 } else {
25416 $loop ++;
25417 }
25418 }
25419
25420 $this->SetFont($font, $style, $szfont, true, true);
25421 $this->Cell($w, 0, $text, 0, 0, "C", 0, '', 0, 0, 0, 'M', 0, false, $OTLdata, $textvar);
25422 }
25423 /* -- END DIRECTW -- */
25424
25425 // ====================================================
25426 // ====================================================
25427
25428 function magic_reverse_dir(&$chunk, $dir, &$chunkOTLdata)
25429 {
25430 /* -- OTL -- */
25431 if ($this->usingCoreFont) {
25432 return 0;
25433 }
25434
25435 if ($chunk == '') {
25436 return 0;
25437 }
25438
25439 if ($this->biDirectional || $dir == 'rtl') {
25440
25441 // check if string contains RTL text
25442 // including any added from OTL tables (in PUA)
25443 $pregRTLchars = $this->pregRTLchars;
25444
25445 if (isset($this->CurrentFont['rtlPUAstr']) && $this->CurrentFont['rtlPUAstr']) {
25446 $pregRTLchars .= $this->CurrentFont['rtlPUAstr'];
25447 }
25448
25449 if (!preg_match("/[" . $pregRTLchars . "]/u", $chunk) && $dir != 'rtl') {
25450 return 0;
25451 } // Chunk doesn't contain RTL characters
25452
25453 $unicode = $this->UTF8StringToArray($chunk, false);
25454
25455 $isStrong = false;
25456 if (empty($chunkOTLdata)) {
25457 $this->getBasicOTLdata($chunkOTLdata, $unicode, $isStrong);
25458 }
25459
25460 $useGPOS = isset($this->CurrentFont['useOTL']) && ($this->CurrentFont['useOTL'] & 0x80);
25461
25462 // NB Returned $chunk may be a shorter string (with adjusted $cOTLdata) by removal of LRE, RLE etc embedding codes.
25463 list($chunk, $rtl_content) = $this->otl->bidiSort($unicode, $chunk, $dir, $chunkOTLdata, $useGPOS);
25464
25465 return $rtl_content;
25466 }
25467
25468 /* -- END OTL -- */
25469 return 0;
25470 }
25471
25472 /* -- OTL -- */
25473
25474 function getBasicOTLdata(&$chunkOTLdata, $unicode, &$is_strong)
25475 {
25476 if (empty($this->otl)) {
25477 $this->otl = new Otl($this, $this->fontCache);
25478 }
25479
25480 $chunkOTLdata['group'] = '';
25481 $chunkOTLdata['GPOSinfo'] = [];
25482 $chunkOTLdata['char_data'] = [];
25483
25484 foreach ($unicode as $char) {
25485
25486 $ucd_record = Ucdn::get_ucd_record($char);
25487 $chunkOTLdata['char_data'][] = ['bidi_class' => $ucd_record[2], 'uni' => $char];
25488
25489 if ($ucd_record[2] == 0 || $ucd_record[2] == 3 || $ucd_record[2] == 4) {
25490 $is_strong = true;
25491 } // contains strong character
25492
25494 $chunkOTLdata['group'] .= 'M';
25495 } elseif ($char == 32 || $char == 12288) {
25496 $chunkOTLdata['group'] .= 'S';
25497 } else {
25498 $chunkOTLdata['group'] .= 'C';
25499 }
25500 }
25501 }
25502
25503 function _setBidiCodes($mode = 'start', $bdf = '')
25504 {
25505 $s = '';
25506
25507 if ($mode == 'end') {
25508
25509 // PDF comes before PDI to close isolate-override (e.g. "LRILROPDFPDI")
25510 if (strpos($bdf, 'PDF') !== false) {
25511 $s .= UtfString::code2utf(0x202C);
25512 } // POP DIRECTIONAL FORMATTING
25513
25514 if (strpos($bdf, 'PDI') !== false) {
25515 $s .= UtfString::code2utf(0x2069);
25516 } // POP DIRECTIONAL ISOLATE
25517
25518 } elseif ($mode == 'start') {
25519
25520 // LRI comes before LRO to open isolate-override (e.g. "LRILROPDFPDI")
25521 if (strpos($bdf, 'LRI') !== false) { // U+2066 LRI
25522 $s .= UtfString::code2utf(0x2066);
25523 } elseif (strpos($bdf, 'RLI') !== false) { // U+2067 RLI
25524 $s .= UtfString::code2utf(0x2067);
25525 } elseif (strpos($bdf, 'FSI') !== false) { // U+2068 FSI
25526 $s .= UtfString::code2utf(0x2068);
25527 }
25528
25529 if (strpos($bdf, 'LRO') !== false) { // U+202D LRO
25530 $s .= UtfString::code2utf(0x202D);
25531 } elseif (strpos($bdf, 'RLO') !== false) { // U+202E RLO
25532 $s .= UtfString::code2utf(0x202E);
25533 } elseif (strpos($bdf, 'LRE') !== false) { // U+202A LRE
25534 $s .= UtfString::code2utf(0x202A);
25535 } elseif (strpos($bdf, 'RLE') !== false) { // U+202B RLE
25536 $s .= UtfString::code2utf(0x202B);
25537 }
25538 }
25539
25540 return $s;
25541 }
25542 /* -- END OTL -- */
25543
25545 {
25546 $subsarray = [];
25547 require __DIR__ . '/../data/subs_win-1252.php';
25548 $this->substitute = [];
25549 foreach ($subsarray as $key => $val) {
25550 $this->substitute[UtfString::code2utf($key)] = $val;
25551 }
25552 }
25553
25555 {
25556 // only substitute characters between tags
25557 if (count($this->substitute)) {
25558 $a = preg_split('/(<.*?>)/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
25559 $html = '';
25560 foreach ($a as $i => $e) {
25561 if ($i % 2 == 0) {
25562 $e = strtr($e, $this->substitute);
25563 }
25564 $html .= $e;
25565 }
25566 }
25567
25568 return $html;
25569 }
25570
25571 function SubstituteCharsSIP(&$writehtml_a, &$writehtml_i, &$writehtml_e)
25572 {
25573 if (preg_match("/^(.*?)([\x{20000}-\x{2FFFF}]+)(.*)/u", $writehtml_e, $m)) {
25574 if (isset($this->CurrentFont['sipext']) && $this->CurrentFont['sipext']) {
25575 $font = $this->CurrentFont['sipext'];
25576 if (!in_array($font, $this->available_unifonts)) {
25577 return 0;
25578 }
25579 $writehtml_a[$writehtml_i] = $writehtml_e = $m[1];
25580 array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
25581 $this->subPos = $writehtml_i;
25582 return 4;
25583 }
25584 }
25585
25586 return 0;
25587 }
25588
25592 function SubstituteCharsNonCore(&$writehtml_a, &$writehtml_i, &$writehtml_e)
25593 {
25594 // Ignore if in Textarea
25595 if ($writehtml_i > 0 && strtolower(substr($writehtml_a[$writehtml_i - 1], 0, 8)) == 'textarea') {
25596 return 0;
25597 }
25598
25599 if (mb_convert_encoding(mb_convert_encoding($writehtml_e, $this->mb_enc, "UTF-8"), "UTF-8", $this->mb_enc) == $writehtml_e) {
25600 return 0;
25601 }
25602
25603 $cw = &$this->CurrentFont['cw'];
25604 $unicode = $this->UTF8StringToArray($writehtml_e, false);
25605 $start = -1;
25606 $end = 0;
25607 $flag = 0;
25608 $ftype = '';
25609 $u = [];
25610
25611 if (!$this->subArrMB) {
25612
25613 require __DIR__ . '/../data/subs_core.php';
25614
25615 $this->subArrMB['a'] = $aarr;
25616 $this->subArrMB['s'] = $sarr;
25617 $this->subArrMB['z'] = $zarr;
25618 }
25619
25620 foreach ($unicode as $c => $char) {
25621
25622 if (($char > 127 || ($flag == 1 && $char == 32)) && $char != 173 && (!isset($this->subArrMB['a'][$char]) || ($flag == 1 && $char == 32)) && ($char < 1536 || ($char > 1791 && $char < 2304) || $char > 3455)) {
25623 if ($flag == 0) {
25624 $start = $c;
25625 }
25626 $flag = 1;
25627 $u[] = $char;
25628 } elseif ($flag > 0) {
25629 $end = $c - 1;
25630 break;
25631 }
25632 }
25633
25634 if ($flag > 0 && !$end) {
25635 $end = count($unicode) - 1;
25636 }
25637
25638 if ($start == -1) {
25639 return 0;
25640 }
25641
25642 // Try in backup subs font
25643 if (!is_array($this->backupSubsFont)) {
25644 $this->backupSubsFont = ["$this->backupSubsFont"];
25645 }
25646
25647 foreach ($this->backupSubsFont as $bsfctr => $bsf) {
25648
25649 if ($this->fonttrans[$bsf] == 'chelvetica' || $this->fonttrans[$bsf] == 'ctimes' || $this->fonttrans[$bsf] == 'ccourier') {
25650 continue;
25651 }
25652
25653 $font = $bsf;
25654 unset($cw);
25655 $cw = '';
25656
25657 if (isset($this->fonts[$font])) {
25658 $cw = &$this->fonts[$font]['cw'];
25659 } elseif ($this->fontCache->has($font . '.cw.dat')) {
25660 $cw = $this->fontCache->load($font . '.cw.dat');
25661 } else {
25662 $prevFontFamily = $this->FontFamily;
25663 $prevFontStyle = $this->currentfontstyle;
25664 $prevFontSizePt = $this->FontSizePt;
25665 $this->SetFont($bsf, '', '', false);
25666 $this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
25667 }
25668
25669 if (!$cw) {
25670 continue;
25671 }
25672
25673 $l = 0;
25674 foreach ($u as $char) {
25675 if ($char == 173 || $this->_charDefined($cw, $char) || ($char > 1536 && $char < 1791) || ($char > 2304 && $char < 3455 )) {
25676 $l++;
25677 } else {
25678 if ($l == 0 && $bsfctr == (count($this->backupSubsFont) - 1)) { // Not found even in last backup font
25679 $cont = mb_substr($writehtml_e, $start + 1);
25680 $writehtml_e = mb_substr($writehtml_e, 0, $start + 1, 'UTF-8');
25681 array_splice($writehtml_a, $writehtml_i + 1, 0, ['', $cont]);
25682 $this->subPos = $writehtml_i + 1;
25683
25684 return 2;
25685 } else {
25686 break;
25687 }
25688 }
25689 }
25690
25691 if ($l > 0) {
25692 $patt = mb_substr($writehtml_e, $start, $l, 'UTF-8');
25693 if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
25694 $writehtml_e = $m[1];
25695 array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
25696 $this->subPos = $writehtml_i + 3;
25697
25698 return 4;
25699 }
25700 }
25701 }
25702
25703 unset($cw);
25704
25705 return 0;
25706 }
25707
25708 function SubstituteCharsMB(&$writehtml_a, &$writehtml_i, &$writehtml_e)
25709 {
25710 // Ignore if in Textarea
25711 if ($writehtml_i > 0 && strtolower(substr($writehtml_a[$writehtml_i - 1], 0, 8)) == 'textarea') {
25712 return 0;
25713 }
25714
25715 $cw = &$this->CurrentFont['cw'];
25716 $unicode = $this->UTF8StringToArray($writehtml_e, false);
25717 $start = -1;
25718 $end = 0;
25719 $flag = 0;
25720 $ftype = '';
25721 $u = [];
25722
25723 foreach ($unicode as $c => $char) {
25724
25725 if (($flag == 0 || $flag == 2) && (!$this->_charDefined($cw, $char) || ($flag == 2 && $char == 32)) && $this->checkSIP && $char > 131071) { // Unicode Plane 2 (SIP)
25726
25727 if (in_array($this->FontFamily, $this->available_CJK_fonts)) {
25728 return 0;
25729 }
25730
25731 if ($flag == 0) {
25732 $start = $c;
25733 }
25734
25735 $flag = 2;
25736 $u[] = $char;
25737
25738 // elseif (($flag == 0 || $flag==1) && $char != 173 && !$this->_charDefined($cw,$char) && ($char<1423 || ($char>3583 && $char < 11263))) {
25739
25740 } elseif (($flag == 0 || $flag == 1) && $char != 173 && (!$this->_charDefined($cw, $char) || ($flag == 1 && $char == 32)) && ($char < 1536 || ($char > 1791 && $char < 2304) || $char > 3455)) {
25741
25742 if ($flag == 0) {
25743 $start = $c;
25744 }
25745
25746 $flag = 1;
25747 $u[] = $char;
25748
25749 } elseif ($flag > 0) {
25750
25751 $end = $c - 1;
25752 break;
25753
25754 }
25755 }
25756
25757 if ($flag > 0 && !$end) {
25758 $end = count($unicode) - 1;
25759 }
25760
25761 if ($start == -1) {
25762 return 0;
25763 }
25764
25765 if ($flag == 2) { // SIP
25766
25767 // Check if current CJK font has a ext-B related font
25768 if (isset($this->CurrentFont['sipext']) && $this->CurrentFont['sipext']) {
25769 $font = $this->CurrentFont['sipext'];
25770 unset($cw);
25771 $cw = '';
25772
25773 if (isset($this->fonts[$font])) {
25774 $cw = &$this->fonts[$font]['cw'];
25775 } elseif ($this->fontCache->has($font . '.cw.dat')) {
25776 $cw = $this->fontCache->load($font . '.cw.dat');
25777 } else {
25778 $prevFontFamily = $this->FontFamily;
25779 $prevFontStyle = $this->currentfontstyle;
25780 $prevFontSizePt = $this->FontSizePt;
25781 $this->SetFont($font, '', '', false);
25782 $this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
25783 }
25784
25785 if (!$cw) {
25786 return 0;
25787 }
25788
25789 $l = 0;
25790 foreach ($u as $char) {
25791 if ($this->_charDefined($cw, $char) || $char > 131071) {
25792 $l++;
25793 } else {
25794 break;
25795 }
25796 }
25797
25798 if ($l > 0) {
25799 $patt = mb_substr($writehtml_e, $start, $l);
25800 if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
25801 $writehtml_e = $m[1];
25802 array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
25803 $this->subPos = $writehtml_i + 3;
25804 return 4;
25805 }
25806 }
25807 }
25808
25809 // Check Backup SIP font (defined in Config\FontVariables)
25810 if (isset($this->backupSIPFont) && $this->backupSIPFont) {
25811
25812 if ($this->currentfontfamily != $this->backupSIPFont) {
25813 $font = $this->backupSIPFont;
25814 } else {
25815 unset($cw);
25816 return 0;
25817 }
25818
25819 unset($cw);
25820 $cw = '';
25821
25822 if (isset($this->fonts[$font])) {
25823 $cw = &$this->fonts[$font]['cw'];
25824 } elseif ($this->fontCache->has($font . '.cw.dat')) {
25825 $cw = $this->fontCache->load($font . '.cw.dat');
25826 } else {
25827 $prevFontFamily = $this->FontFamily;
25828 $prevFontStyle = $this->currentfontstyle;
25829 $prevFontSizePt = $this->FontSizePt;
25830 $this->SetFont($this->backupSIPFont, '', '', false);
25831 $this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
25832 }
25833
25834 if (!$cw) {
25835 return 0;
25836 }
25837
25838 $l = 0;
25839 foreach ($u as $char) {
25840 if ($this->_charDefined($cw, $char) || $char > 131071) {
25841 $l++;
25842 } else {
25843 break;
25844 }
25845 }
25846
25847 if ($l > 0) {
25848 $patt = mb_substr($writehtml_e, $start, $l);
25849 if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
25850 $writehtml_e = $m[1];
25851 array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
25852 $this->subPos = $writehtml_i + 3;
25853 return 4;
25854 }
25855 }
25856 }
25857
25858 return 0;
25859 }
25860
25861 // FIRST TRY CORE FONTS (when appropriate)
25862 if (!$this->PDFA && !$this->PDFX && !$this->biDirectional) { // mPDF 6
25863 $repl = [];
25864 if (!$this->subArrMB) {
25865 require __DIR__ . '/../data/subs_core.php';
25866 $this->subArrMB['a'] = $aarr;
25867 $this->subArrMB['s'] = $sarr;
25868 $this->subArrMB['z'] = $zarr;
25869 }
25870 if (isset($this->subArrMB['a'][$u[0]])) {
25871 $font = 'tta';
25872 $ftype = 'C';
25873 foreach ($u as $char) {
25874 if (isset($this->subArrMB['a'][$char])) {
25875 $repl[] = $this->subArrMB['a'][$char];
25876 } else {
25877 break;
25878 }
25879 }
25880 } elseif (isset($this->subArrMB['z'][$u[0]])) {
25881 $font = 'ttz';
25882 $ftype = 'C';
25883 foreach ($u as $char) {
25884 if (isset($this->subArrMB['z'][$char])) {
25885 $repl[] = $this->subArrMB['z'][$char];
25886 } else {
25887 break;
25888 }
25889 }
25890 } elseif (isset($this->subArrMB['s'][$u[0]])) {
25891 $font = 'tts';
25892 $ftype = 'C';
25893 foreach ($u as $char) {
25894 if (isset($this->subArrMB['s'][$char])) {
25895 $repl[] = $this->subArrMB['s'][$char];
25896 } else {
25897 break;
25898 }
25899 }
25900 }
25901 if ($ftype == 'C') {
25902 $patt = mb_substr($writehtml_e, $start, count($repl));
25903 if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
25904 $writehtml_e = $m[1];
25905 array_splice($writehtml_a, $writehtml_i + 1, 0, [$font, implode('|', $repl), '/' . $font, $m[3]]); // e.g. <tts>
25906 $this->subPos = $writehtml_i + 3;
25907 return 4;
25908 }
25909 return 0;
25910 }
25911 }
25912
25913 // LASTLY TRY IN BACKUP SUBS FONT
25914 if (!is_array($this->backupSubsFont)) {
25915 $this->backupSubsFont = ["$this->backupSubsFont"];
25916 }
25917
25918 foreach ($this->backupSubsFont as $bsfctr => $bsf) {
25919 if ($this->currentfontfamily != $bsf) {
25920 $font = $bsf;
25921 } else {
25922 continue;
25923 }
25924
25925 unset($cw);
25926 $cw = '';
25927
25928 if (isset($this->fonts[$font])) {
25929 $cw = &$this->fonts[$font]['cw'];
25930 } elseif ($this->fontCache->has($font . '.cw.dat')) {
25931 $cw = $this->fontCache->load($font . '.cw.dat');
25932 } else {
25933 $prevFontFamily = $this->FontFamily;
25934 $prevFontStyle = $this->currentfontstyle;
25935 $prevFontSizePt = $this->FontSizePt;
25936 $this->SetFont($bsf, '', '', false);
25937 $this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt, false);
25938 if ($this->fontCache->has($font . '.cw.dat')) {
25939 $cw = $this->fontCache->load($font . '.cw.dat');
25940 }
25941 }
25942
25943 if (!$cw) {
25944 continue;
25945 }
25946
25947 $l = 0;
25948 foreach ($u as $char) {
25949 if ($char == 173 || $this->_charDefined($cw, $char) || ($char > 1536 && $char < 1791) || ($char > 2304 && $char < 3455 )) { // Arabic and Indic
25950 $l++;
25951 } else {
25952 if ($l == 0 && $bsfctr == (count($this->backupSubsFont) - 1)) { // Not found even in last backup font
25953 $cont = mb_substr($writehtml_e, $start + 1);
25954 $writehtml_e = mb_substr($writehtml_e, 0, $start + 1);
25955 array_splice($writehtml_a, $writehtml_i + 1, 0, ['', $cont]);
25956 $this->subPos = $writehtml_i + 1;
25957 return 2;
25958 } else {
25959 break;
25960 }
25961 }
25962 }
25963
25964 if ($l > 0) {
25965 $patt = mb_substr($writehtml_e, $start, $l);
25966 if (preg_match("/(.*?)(" . preg_quote($patt, '/') . ")(.*)/u", $writehtml_e, $m)) {
25967 $writehtml_e = $m[1];
25968 array_splice($writehtml_a, $writehtml_i + 1, 0, ['span style="font-family: ' . $font . '"', $m[2], '/span', $m[3]]);
25969 $this->subPos = $writehtml_i + 3;
25970 return 4;
25971 }
25972 }
25973 }
25974
25975 unset($cw);
25976
25977 return 0;
25978 }
25979
25981 {
25982 $entarr = include __DIR__ . '/../data/entity_substitutions.php';
25983
25984 foreach ($entarr as $key => $val) {
25985 $this->entsearch[] = '&' . $key . ';';
25986 $this->entsubstitute[] = UtfString::code2utf($val);
25987 }
25988 }
25989
25991 {
25992 // converts html_entities > ASCII 127 to unicode
25993 // Leaves in particular &lt; to distinguish from tag marker
25994 if (count($this->entsearch)) {
25995 $html = str_replace($this->entsearch, $this->entsubstitute, $html);
25996 }
25997
25998 return $html;
25999 }
26000
26004 function is_utf8(&$string)
26005 {
26006 if ($string === mb_convert_encoding(mb_convert_encoding($string, "UTF-32", "UTF-8"), "UTF-8", "UTF-32")) {
26007 return true;
26008 }
26009
26010 if ($this->ignore_invalid_utf8) {
26011 $string = mb_convert_encoding(mb_convert_encoding($string, "UTF-32", "UTF-8"), "UTF-8", "UTF-32");
26012 return true;
26013 }
26014
26015 return false;
26016 }
26017
26026 function purify_utf8($html, $lo = true)
26027 {
26028 if (!$this->is_utf8($html)) {
26029
26030 while (mb_convert_encoding(mb_convert_encoding($html, "UTF-32", "UTF-8"), "UTF-8", "UTF-32") != $html) {
26031
26032 $a = @iconv('UTF-8', 'UTF-8', $html);
26033 $error = error_get_last();
26034 if ($error && $error['message'] === 'iconv(): Detected an illegal character in input string') {
26035 throw new \Mpdf\MpdfException('Invalid input characters. Did you set $mpdf->in_charset properly?');
26036 }
26037
26038 $pos = $start = strlen($a);
26039 $err = '';
26040 while (ord(substr($html, $pos, 1)) > 128) {
26041 $err .= '[[#' . ord(substr($html, $pos, 1)) . ']]';
26042 $pos++;
26043 }
26044
26045 $this->logger->error($err, ['context' => LogContext::UTF8]);
26046 $html = substr($html, $pos);
26047 }
26048
26049 throw new \Mpdf\MpdfException("HTML contains invalid UTF-8 character(s). See log for further details");
26050 }
26051
26052 $html = preg_replace("/\r/", "", $html);
26053
26054 // converts html_entities > ASCII 127 to UTF-8
26055 // Leaves in particular &lt; to distinguish from tag marker
26056 $html = $this->SubstituteHiEntities($html);
26057
26058 // converts all &#nnn; or &#xHHH; to UTF-8 multibyte
26059 // If $lo==true then includes ASCII < 128
26061
26062 return $html;
26063 }
26064
26068 function purify_utf8_text($txt)
26069 {
26070 // Make sure UTF-8 string of characters
26071 if (!$this->is_utf8($txt)) {
26072 throw new \Mpdf\MpdfException("Text contains invalid UTF-8 character(s)");
26073 }
26074
26075 $txt = preg_replace("/\r/", "", $txt);
26076
26077 return ($txt);
26078 }
26079
26081 {
26082 // converts txt_entities > ASCII 127 to UTF-8
26083 // Leaves in particular &lt; to distinguish from tag marker
26084 $txt = $this->SubstituteHiEntities($txt);
26085
26086 // converts all &#nnn; or &#xHHH; to UTF-8 multibyte
26087 $txt = UtfString::strcode2utf($txt);
26088
26089 $txt = $this->lesser_entity_decode($txt);
26090 return ($txt);
26091 }
26092
26093 /* -- BARCODES -- */
26100 function WriteBarcode($code, $showtext = 1, $x = '', $y = '', $size = 1, $border = 0, $paddingL = 1, $paddingR = 1, $paddingT = 2, $paddingB = 2, $height = 1, $bgcol = false, $col = false, $btype = 'ISBN', $supplement = '0', $supplement_code = '', $k = 1)
26101 {
26102 if (empty($code)) {
26103 return;
26104 }
26105
26106 $codestr = $code;
26107 $code = preg_replace('/\-/', '', $code);
26108
26109 $this->barcode = new Barcode();
26110 if ($btype == 'ISSN' || $btype == 'ISBN') {
26111 $arrcode = $this->barcode->getBarcodeArray($code, 'EAN13');
26112 } else {
26113 $arrcode = $this->barcode->getBarcodeArray($code, $btype);
26114 }
26115
26116 if ($arrcode === false) {
26117 throw new \Mpdf\MpdfException('Error in barcode string: ' . $codestr);
26118 }
26119
26120 if ((($btype === 'EAN13' || $btype === 'ISBN' || $btype === 'ISSN') && strlen($code) === 12)
26121 || ($btype == 'UPCA' && strlen($code) === 11)
26122 || ($btype == 'UPCE' && strlen($code) === 11)
26123 || ($btype == 'EAN8' && strlen($code) === 7)) {
26124
26125 $code .= $arrcode['checkdigit'];
26126
26127 if (stristr($codestr, '-')) {
26128 $codestr .= '-' . $arrcode['checkdigit'];
26129 } else {
26130 $codestr .= $arrcode['checkdigit'];
26131 }
26132 }
26133
26134 if ($btype === 'ISBN') {
26135 $codestr = 'ISBN ' . $codestr;
26136 }
26137
26138 if ($btype === 'ISSN') {
26139 $codestr = 'ISSN ' . $codestr;
26140 }
26141
26142 if (empty($x)) {
26143 $x = $this->x;
26144 }
26145
26146 if (empty($y)) {
26147 $y = $this->y;
26148 }
26149
26150 // set foreground color
26151 $prevDrawColor = $this->DrawColor;
26152 $prevTextColor = $this->TextColor;
26153 $prevFillColor = $this->FillColor;
26154
26155 $lw = $this->LineWidth;
26156 $this->SetLineWidth(0.01);
26157
26158 $size /= $k; // in case resized in a table
26159
26160 $xres = $arrcode['nom-X'] * $size;
26161 $llm = $arrcode['lightmL'] * $arrcode['nom-X'] * $size; // Left Light margin
26162 $rlm = $arrcode['lightmR'] * $arrcode['nom-X'] * $size; // Right Light margin
26163
26164 $bcw = ($arrcode["maxw"] * $xres); // Barcode width = Should always be 31.35mm * $size
26165
26166 $fbw = $bcw + $llm + $rlm; // Full barcode width incl. light margins
26167 $ow = $fbw + $paddingL + $paddingR; // Full overall width incl. user-defined padding
26168
26169 $fbwi = $fbw - 2; // Full barcode width incl. light margins - 2mm - for isbn string
26170 // cf. http://www.gs1uk.org/downloads/bar_code/Bar coding getting it right.pdf
26171 $num_height = 3 * $size; // Height of numerals
26172 $fbh = $arrcode['nom-H'] * $size * $height; // Full barcode height incl. numerals
26173 $bch = $fbh - (1.5 * $size); // Barcode height of bars (3mm for numerals)
26174
26175 if (($btype == 'EAN13' && $showtext) || $btype == 'ISSN' || $btype == 'ISBN') { // Add height for ISBN string + margin from top of bars
26176 $tisbnm = 1.5 * $size; // Top margin between isbn (if shown) & bars
26177 $codestr_fontsize = 2.1 * $size;
26178 $paddingT += $codestr_fontsize + $tisbnm;
26179 }
26180
26181 $oh = $fbh + $paddingT + $paddingB; // Full overall height incl. user-defined padding
26182
26183 // PRINT border background color
26184 $xpos = $x;
26185 $ypos = $y;
26186
26187 if ($col) {
26188 $this->SetDColor($col);
26189 $this->SetTColor($col);
26190 } else {
26191 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26192 $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26193 }
26194
26195 if ($bgcol) {
26196 $this->SetFColor($bgcol);
26197 } else {
26198 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
26199 }
26200
26201 if (!$bgcol && !$col) { // fn. called directly - not via HTML
26202
26203 if ($border) {
26204 $fillb = 'DF';
26205 } else {
26206 $fillb = 'F';
26207 }
26208
26209 $this->Rect($xpos, $ypos, $ow, $oh, $fillb);
26210 }
26211
26212
26213 // PRINT BARS
26214 $xpos = $x + $paddingL + $llm;
26215 $ypos = $y + $paddingT;
26216
26217 if ($col) {
26218 $this->SetFColor($col);
26219 } else {
26220 $this->SetFColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26221 }
26222
26223 if ($arrcode !== false) {
26224 foreach ($arrcode["bcode"] as $v) {
26225 $bw = ($v["w"] * $xres);
26226 if ($v["t"]) {
26227 // draw a vertical bar
26228 $this->Rect($xpos, $ypos, $bw, $bch, 'F');
26229 }
26230 $xpos += $bw;
26231 }
26232 }
26233
26234 // print text
26235 $prevFontFamily = $this->FontFamily;
26236 $prevFontStyle = $this->FontStyle;
26237 $prevFontSizePt = $this->FontSizePt;
26238
26239 // ISBN string
26240 if (($btype === 'EAN13' && $showtext) || $btype === 'ISBN' || $btype === 'ISSN') {
26241
26242 if ($this->onlyCoreFonts) {
26243 $this->SetFont('chelvetica');
26244 } else {
26245 $this->SetFont('sans');
26246 }
26247
26248 if ($bgcol) {
26249 $this->SetFColor($bgcol);
26250 } else {
26251 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
26252 }
26253
26254 $this->x = $x + $paddingL + 1; // 1mm left margin (cf. $fbwi above)
26255
26256 // max width is $fbwi
26257 $loop = 0;
26258 while ($loop == 0) {
26259 $this->SetFontSize($codestr_fontsize * 1.4 * Mpdf::SCALE, false); // don't write
26260 $sz = $this->GetStringWidth($codestr);
26261
26262 if ($sz > $fbwi) {
26263 $codestr_fontsize -= 0.1;
26264 } else {
26265 $loop ++;
26266 }
26267 }
26268
26269 $this->SetFont('', '', $codestr_fontsize * 1.4 * Mpdf::SCALE, true, true); // * 1.4 because font height is only 7/10 of given mm
26270 // WORD SPACING
26271 if ($fbwi > $sz) {
26272 $xtra = $fbwi - $sz;
26273 $charspacing = $xtra / (strlen($codestr) - 1);
26274 if ($charspacing) {
26275 $this->writer->write(sprintf('BT %.3F Tc ET', $charspacing * Mpdf::SCALE));
26276 }
26277 }
26278
26279 $this->y = $y + $paddingT - ($codestr_fontsize ) - $tisbnm;
26280 $this->Cell($fbw, $codestr_fontsize, $codestr);
26281
26282 if ($charspacing) {
26283 $this->writer->write('BT 0 Tc ET');
26284 }
26285 }
26286
26287
26288 // Bottom NUMERALS
26289 // mPDF 5.7.4
26290 if ($this->onlyCoreFonts) {
26291 $this->SetFont('ccourier');
26292 $fh = 1.3;
26293 } else {
26294 $this->SetFont('ocrb');
26295 $fh = 1.06;
26296 }
26297
26298 $charRO = '';
26299
26300 if ($btype === 'EAN13' || $btype === 'ISBN' || $btype === 'ISSN') {
26301
26302 $outerfontsize = 3; // Inner fontsize = 3
26303 $outerp = $xres * 4;
26304 $innerp = $xres * 2.5;
26305 $textw = ($bcw * 0.5) - $outerp - $innerp;
26306 $chars = 6; // number of numerals in each half
26307 $charLO = substr($code, 0, 1); // Left Outer
26308 $charLI = substr($code, 1, 6); // Left Inner
26309 $charRI = substr($code, 7, 6); // Right Inner
26310
26311 if (!$supplement) {
26312 $charRO = '>'; // Right Outer
26313 }
26314
26315 } elseif ($btype === 'UPCA') {
26316
26317 $outerfontsize = 2.3; // Inner fontsize = 3
26318 $outerp = $xres * 10;
26319 $innerp = $xres * 2.5;
26320 $textw = ($bcw * 0.5) - $outerp - $innerp;
26321 $chars = 5;
26322 $charLO = substr($code, 0, 1); // Left Outer
26323 $charLI = substr($code, 1, 5); // Left Inner
26324 $charRI = substr($code, 6, 5); // Right Inner
26325 $charRO = substr($code, 11, 1); // Right Outer
26326
26327 } elseif ($btype === 'UPCE') {
26328
26329 $outerfontsize = 2.3; // Inner fontsize = 3
26330 $outerp = $xres * 4;
26331 $innerp = 0;
26332 $textw = ($bcw * 0.5) - $outerp - $innerp;
26333 $chars = 3;
26334 $upce_code = $arrcode['code'];
26335 $charLO = substr($code, 0, 1); // Left Outer
26336 $charLI = substr($upce_code, 0, 3); // Left Inner
26337 $charRI = substr($upce_code, 3, 3); // Right Inner
26338 $charRO = substr($code, 11, 1); // Right Outer
26339
26340 } elseif ($btype === 'EAN8') {
26341
26342 $outerfontsize = 3; // Inner fontsize = 3
26343 $outerp = $xres * 4;
26344 $innerp = $xres * 2.5;
26345 $textw = ($bcw * 0.5) - $outerp - $innerp;
26346 $chars = 4;
26347 $charLO = '<'; // Left Outer
26348 $charLI = substr($code, 0, 4); // Left Inner
26349 $charRI = substr($code, 4, 4); // Right Inner
26350
26351 if (!$supplement) {
26352 $charRO = '>'; // Right Outer
26353 }
26354 }
26355
26356 $this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
26357
26358 if (!$this->usingCoreFont) { // character width at 3mm
26359 $cw = $this->_getCharWidth($this->CurrentFont['cw'], 32) * 3 * $fh * $size / 1000;
26360 } else {
26361 $cw = 600 * 3 * $fh * $size / 1000;
26362 }
26363
26364 // Outer left character
26365 $y_text = $y + $paddingT + $bch - ($num_height / 2);
26366 $y_text_outer = $y + $paddingT + $bch - ($num_height * ($outerfontsize / 3) / 2);
26367
26368 $this->x = $x + $paddingL - ($cw * ($outerfontsize / 3) * 0.1); // 0.1 is correction as char does not fill full width;
26369 $this->y = $y_text_outer;
26370 $this->Cell($cw, $num_height, $charLO);
26371
26372 // WORD SPACING for inner chars
26373 $xtra = $textw - ($cw * $chars);
26374 $charspacing = $xtra / ($chars - 1);
26375 if ($charspacing) {
26376 $this->writer->write(sprintf('BT %.3F Tc ET', $charspacing * Mpdf::SCALE));
26377 }
26378
26379 if ($bgcol) {
26380 $this->SetFColor($bgcol);
26381 } else {
26382 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
26383 }
26384
26385 $this->SetFontSize(3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
26386
26387 // Inner left half characters
26388 $this->x = $x + $paddingL + $llm + $outerp;
26389 $this->y = $y_text;
26390 $this->Cell($textw, $num_height, $charLI, 0, 0, '', 1);
26391
26392 // Inner right half characters
26393 $this->x = $x + $paddingL + $llm + ($bcw * 0.5) + $innerp;
26394 $this->y = $y_text;
26395 $this->Cell($textw, $num_height, $charRI, 0, 0, '', 1);
26396
26397 if ($charspacing) {
26398 $this->writer->write('BT 0 Tc ET');
26399 }
26400
26401 // Outer Right character
26402 $this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
26403
26404 $this->x = $x + $paddingL + $llm + $bcw + $rlm - ($cw * ($outerfontsize / 3) * 0.9); // 0.9 is correction as char does not fill full width
26405 $this->y = $y_text_outer;
26406 $this->Cell($cw * ($outerfontsize / 3), $num_height, $charRO, 0, 0, 'R');
26407
26408 if ($supplement) { // EAN-2 or -5 Supplement
26409 // PRINT BARS
26410 $supparrcode = $this->barcode->getBarcodeArray($supplement_code, 'EAN' . $supplement);
26411
26412 if ($supparrcode === false) {
26413 throw new \Mpdf\MpdfException('Error in barcode string (supplement): ' . $codestr . ' ' . $supplement_code);
26414 }
26415
26416 if (strlen($supplement_code) != $supplement) {
26417 throw new \Mpdf\MpdfException('Barcode supplement incorrect: ' . $supplement_code);
26418 }
26419
26420 $llm = $fbw - (($arrcode['lightmR'] - $supparrcode['sepM']) * $arrcode['nom-X'] * $size); // Left Light margin
26421 $rlm = $arrcode['lightmR'] * $arrcode['nom-X'] * $size; // Right Light margin
26422
26423 $bcw = ($supparrcode["maxw"] * $xres); // Barcode width = Should always be 31.35mm * $size
26424
26425 $fbw = $bcw + $llm + $rlm; // Full barcode width incl. light margins
26426 $ow = $fbw + $paddingL + $paddingR; // Full overall width incl. user-defined padding
26427 $bch = $fbh - (1.5 * $size) - ($num_height + 0.5); // Barcode height of bars (3mm for numerals)
26428
26429 $xpos = $x + $paddingL + $llm;
26430 $ypos = $y + $paddingT + $num_height + 0.5;
26431
26432 if ($col) {
26433 $this->SetFColor($col);
26434 } else {
26435 $this->SetFColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26436 }
26437
26438 if ($supparrcode !== false) {
26439 foreach ($supparrcode["bcode"] as $v) {
26440 $bw = ($v["w"] * $xres);
26441 if ($v["t"]) {
26442 // draw a vertical bar
26443 $this->Rect($xpos, $ypos, $bw, $bch, 'F');
26444 }
26445 $xpos += $bw;
26446 }
26447 }
26448
26449 // Characters
26450 if ($bgcol) {
26451 $this->SetFColor($bgcol);
26452 } else {
26453 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
26454 }
26455
26456 $this->SetFontSize(3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
26457 $this->x = $x + $paddingL + $llm;
26458 $this->y = $y + $paddingT;
26459 $this->Cell($bcw, $num_height, $supplement_code, 0, 0, 'C');
26460
26461 // Outer Right character (light margin)
26462 $this->SetFontSize(($outerfontsize / 3) * 3 * $fh * $size * Mpdf::SCALE); // 3mm numerals (FontSize is larger to account for space above/below characters)
26463 $this->x = $x + $paddingL + $llm + $bcw + $rlm - ($cw * 0.9); // 0.9 is correction as char does not fill full width
26464 $this->y = $y + $paddingT;
26465 $this->Cell($cw * ($outerfontsize / 3), $num_height, '>', 0, 0, 'R');
26466 }
26467
26468 // Restore **************
26469 $this->SetFont($prevFontFamily, $prevFontStyle, $prevFontSizePt);
26470 $this->DrawColor = $prevDrawColor;
26471 $this->TextColor = $prevTextColor;
26472 $this->FillColor = $prevFillColor;
26473 $this->SetLineWidth($lw);
26474 $this->SetY($y);
26475 }
26476
26480 function WriteBarcode2($code, $x = '', $y = '', $size = 1, $height = 1, $bgcol = false, $col = false, $btype = 'IMB', $print_ratio = '', $k = 1, $quiet_zone_left = null, $quiet_zone_right = null)
26481 {
26482 if (empty($code)) {
26483 return;
26484 }
26485
26486 $this->barcode = new Barcode();
26487 $arrcode = $this->barcode->getBarcodeArray($code, $btype, $print_ratio, $quiet_zone_left, $quiet_zone_right);
26488
26489 if (empty($x)) {
26490 $x = $this->x;
26491 }
26492
26493 if (empty($y)) {
26494 $y = $this->y;
26495 }
26496
26497 $prevDrawColor = $this->DrawColor;
26498 $prevTextColor = $this->TextColor;
26499 $prevFillColor = $this->FillColor;
26500 $lw = $this->LineWidth;
26501 $this->SetLineWidth(0.01);
26502 $size /= $k; // in case resized in a table
26503 $xres = $arrcode['nom-X'] * $size;
26504
26505 if ($btype === 'IMB' || $btype === 'RM4SCC' || $btype === 'KIX' || $btype === 'POSTNET' || $btype === 'PLANET') {
26506 $llm = $arrcode['quietL'] / $k; // Left Quiet margin
26507 $rlm = $arrcode['quietR'] / $k; // Right Quiet margin
26508 $tlm = $blm = $arrcode['quietTB'] / $k;
26509 $height = 1; // Overrides
26510 } elseif (in_array($btype, ['C128A', 'C128B', 'C128C', 'C128RAW', 'EAN128A', 'EAN128B', 'EAN128C', 'C39', 'C39+', 'C39E', 'C39E+', 'S25', 'S25+', 'I25', 'I25+', 'I25B', 'I25B+', 'C93', 'MSI', 'MSI+', 'CODABAR', 'CODE11'])) {
26511 $llm = $arrcode['lightmL'] * $xres; // Left Quiet margin
26512 $rlm = $arrcode['lightmR'] * $xres; // Right Quiet margin
26513 $tlm = $blm = $arrcode['lightTB'] * $xres * $height;
26514 }
26515
26516 $bcw = ($arrcode["maxw"] * $xres);
26517 $fbw = $bcw + $llm + $rlm; // Full barcode width incl. light margins
26518
26519 $bch = ($arrcode["nom-H"] * $size * $height);
26520 $fbh = $bch + $tlm + $blm; // Full barcode height
26521
26522 // PRINT border background color
26523 $xpos = $x;
26524 $ypos = $y;
26525
26526 if ($col) {
26527 $this->SetDColor($col);
26528 $this->SetTColor($col);
26529 } else {
26530 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26531 $this->SetTColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26532 }
26533
26534 if ($bgcol) {
26535 $this->SetFColor($bgcol);
26536 } else {
26537 $this->SetFColor($this->colorConverter->convert(255, $this->PDFAXwarnings));
26538 }
26539
26540 // PRINT BARS
26541 if ($col) {
26542 $this->SetFColor($col);
26543 } else {
26544 $this->SetFColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
26545 }
26546 $xpos = $x + $llm;
26547
26548 if ($arrcode !== false) {
26549 foreach ($arrcode["bcode"] as $v) {
26550 $bw = ($v["w"] * $xres);
26551 if ($v["t"]) {
26552 $ypos = $y + $tlm + ($bch * $v['p'] / $arrcode['maxh']);
26553 $this->Rect($xpos, $ypos, $bw, ($v['h'] * $bch / $arrcode['maxh']), 'F');
26554 }
26555 $xpos += $bw;
26556 }
26557 }
26558
26559 // PRINT BEARER BARS
26560 if ($btype == 'I25B' || $btype == 'I25B+') {
26561 $this->Rect($x, $y, $fbw, ($arrcode['lightTB'] * $xres * $height), 'F');
26562 $this->Rect($x, $y + $tlm + $bch, $fbw, ($arrcode['lightTB'] * $xres * $height), 'F');
26563 }
26564
26565 // Restore **************
26566 $this->DrawColor = $prevDrawColor;
26567 $this->TextColor = $prevTextColor;
26568 $this->FillColor = $prevFillColor;
26569 $this->SetLineWidth($lw);
26570 $this->SetY($y);
26571 }
26572 /* -- END BARCODES -- */
26573
26574 function StartTransform($returnstring = false)
26575 {
26576 if ($returnstring) {
26577 return('q');
26578 } else {
26579 $this->writer->write('q');
26580 }
26581 }
26582
26583 function StopTransform($returnstring = false)
26584 {
26585 if ($returnstring) {
26586 return('Q');
26587 } else {
26588 $this->writer->write('Q');
26589 }
26590 }
26591
26592 function transformScale($s_x, $s_y, $x = '', $y = '', $returnstring = false)
26593 {
26594 if ($x === '') {
26595 $x = $this->x;
26596 }
26597
26598 if ($y === '') {
26599 $y = $this->y;
26600 }
26601
26602 if (($s_x == 0) or ( $s_y == 0)) {
26603 throw new \Mpdf\MpdfException('Please do not use values equal to zero for scaling');
26604 }
26605
26606 $y = ($this->h - $y) * Mpdf::SCALE;
26607 $x *= Mpdf::SCALE;
26608
26609 // calculate elements of transformation matrix
26610 $s_x /= 100;
26611 $s_y /= 100;
26612 $tm = [];
26613 $tm[0] = $s_x;
26614 $tm[1] = 0;
26615 $tm[2] = 0;
26616 $tm[3] = $s_y;
26617 $tm[4] = $x * (1 - $s_x);
26618 $tm[5] = $y * (1 - $s_y);
26619
26620 // scale the coordinate system
26621 if ($returnstring) {
26622 return($this->_transform($tm, true));
26623 } else {
26624 $this->_transform($tm);
26625 }
26626 }
26627
26628 function transformTranslate($t_x, $t_y, $returnstring = false)
26629 {
26630 // calculate elements of transformation matrix
26631 $tm = [];
26632 $tm[0] = 1;
26633 $tm[1] = 0;
26634 $tm[2] = 0;
26635 $tm[3] = 1;
26636 $tm[4] = $t_x * Mpdf::SCALE;
26637 $tm[5] = -$t_y * Mpdf::SCALE;
26638
26639 // translate the coordinate system
26640 if ($returnstring) {
26641 return($this->_transform($tm, true));
26642 } else {
26643 $this->_transform($tm);
26644 }
26645 }
26646
26647 function transformRotate($angle, $x = '', $y = '', $returnstring = false)
26648 {
26649 if ($x === '') {
26650 $x = $this->x;
26651 }
26652
26653 if ($y === '') {
26654 $y = $this->y;
26655 }
26656
26657 $angle = -$angle;
26658 $y = ($this->h - $y) * Mpdf::SCALE;
26659 $x *= Mpdf::SCALE;
26660
26661 // calculate elements of transformation matrix
26662 $tm = [];
26663 $tm[0] = cos(deg2rad($angle));
26664 $tm[1] = sin(deg2rad($angle));
26665 $tm[2] = -$tm[1];
26666 $tm[3] = $tm[0];
26667 $tm[4] = $x + $tm[1] * $y - $tm[0] * $x;
26668 $tm[5] = $y - $tm[0] * $y - $tm[1] * $x;
26669
26670 // rotate the coordinate system around ($x,$y)
26671 if ($returnstring) {
26672 return $this->_transform($tm, true);
26673 } else {
26674 $this->_transform($tm);
26675 }
26676 }
26677
26681 function transformSkew($angle_x, $angle_y, $x = '', $y = '', $returnstring = false)
26682 {
26683 if ($x === '') {
26684 $x = $this->x;
26685 }
26686
26687 if ($y === '') {
26688 $y = $this->y;
26689 }
26690
26691 $angle_x = -$angle_x;
26692 $angle_y = -$angle_y;
26693
26694 $x *= Mpdf::SCALE;
26695 $y = ($this->h - $y) * Mpdf::SCALE;
26696
26697 // calculate elements of transformation matrix
26698 $tm = [];
26699 $tm[0] = 1;
26700 $tm[1] = tan(deg2rad($angle_y));
26701 $tm[2] = tan(deg2rad($angle_x));
26702 $tm[3] = 1;
26703 $tm[4] = -$tm[2] * $y;
26704 $tm[5] = -$tm[1] * $x;
26705
26706 // skew the coordinate system
26707 if ($returnstring) {
26708 return $this->_transform($tm, true);
26709 } else {
26710 $this->_transform($tm);
26711 }
26712 }
26713
26714 function _transform($tm, $returnstring = false)
26715 {
26716 if ($returnstring) {
26717 return(sprintf('%.4F %.4F %.4F %.4F %.4F %.4F cm', $tm[0], $tm[1], $tm[2], $tm[3], $tm[4], $tm[5]));
26718 } else {
26719 $this->writer->write(sprintf('%.4F %.4F %.4F %.4F %.4F %.4F cm', $tm[0], $tm[1], $tm[2], $tm[3], $tm[4], $tm[5]));
26720 }
26721 }
26722
26723 // AUTOFONT =========================
26725 {
26726 if ($this->onlyCoreFonts) {
26727 return $html;
26728 }
26729
26730 $n = '';
26731 $a = preg_split('/<(.*?)>/ms', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
26732 foreach ($a as $i => $e) {
26733 if ($i % 2 == 0) {
26734
26735 // ignore if in Textarea
26736 if ($i > 0 && strtolower(substr($a[$i - 1], 1, 8)) == 'textarea') {
26737 $a[$i] = $e;
26738 continue;
26739 }
26740
26741 $e = UtfString::strcode2utf($e);
26742 $e = $this->lesser_entity_decode($e);
26743
26744 $earr = $this->UTF8StringToArray($e, false);
26745
26746 $scriptblock = 0;
26747 $scriptblocks = [];
26748 $scriptblocks[0] = 0;
26749 $chardata = [];
26750 $subchunk = 0;
26751 $charctr = 0;
26752
26753 foreach ($earr as $char) {
26754
26755 $ucd_record = Ucdn::get_ucd_record($char);
26756 $sbl = $ucd_record[6];
26757
26758 if ($sbl && $sbl != 40 && $sbl != 102) {
26759 if ($scriptblock == 0) {
26760 $scriptblock = $sbl;
26761 $scriptblocks[$subchunk] = $scriptblock;
26762 } elseif ($scriptblock > 0 && $scriptblock != $sbl) {
26763 // NEW (non-common) Script encountered in this chunk.
26764 // Start a new subchunk
26765 $subchunk++;
26766 $scriptblock = $sbl;
26767 $charctr = 0;
26768 $scriptblocks[$subchunk] = $scriptblock;
26769 }
26770 }
26771
26772 $chardata[$subchunk][$charctr]['script'] = $sbl;
26773 $chardata[$subchunk][$charctr]['uni'] = $char;
26774 $charctr++;
26775 }
26776
26777 // If scriptblock[x] = common & non-baseScript
26778 // and scriptblock[x+1] = baseScript
26779 // Move common script from end of x to start of x+1
26780 for ($sch = 0; $sch < $subchunk; $sch++) {
26781 if ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->baseScript && $scriptblocks[$sch + 1] == $this->baseScript) {
26782 $end = count($chardata[$sch]) - 1;
26783 while ($chardata[$sch][$end]['script'] == 0 && $end > 1) { // common script
26784 $tmp = array_pop($chardata[$sch]);
26785 array_unshift($chardata[$sch + 1], $tmp);
26786 $end--;
26787 }
26788 }
26789 }
26790
26791 $o = '';
26792 for ($sch = 0; $sch <= $subchunk; $sch++) {
26793
26794 if (isset($chardata[$sch])) {
26795 $s = '';
26796 for ($j = 0; $j < count($chardata[$sch]); $j++) {
26797 $s .= UtfString::code2utf($chardata[$sch][$j]['uni']);
26798 }
26799
26800 // ZZZ99 Undo lesser_entity_decode as above - but only for <>&
26801 $s = str_replace("&", "&amp;", $s);
26802 $s = str_replace("<", "&lt;", $s);
26803 $s = str_replace(">", "&gt;", $s);
26804
26805 // Check Vietnamese if Latin script - even if Basescript
26806 if ($scriptblocks[$sch] == Ucdn::SCRIPT_LATIN && $this->autoVietnamese && preg_match("/([" . $this->scriptToLanguage->getLanguageDelimiters('viet') . "])/u", $s)) {
26807 $o .= '<span lang="vi" class="lang_vi">' . $s . '</span>';
26808 } elseif ($scriptblocks[$sch] == Ucdn::SCRIPT_ARABIC && $this->autoArabic) { // Check Arabic for different languages if Arabic script - even if Basescript
26809 if (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('sindhi') . "]/u", $s)) {
26810 $o .= '<span lang="sd" class="lang_sd">' . $s . '</span>';
26811 } elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('urdu') . "]/u", $s)) {
26812 $o .= '<span lang="ur" class="lang_ur">' . $s . '</span>';
26813 } elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('pashto') . "]/u", $s)) {
26814 $o .= '<span lang="ps" class="lang_ps">' . $s . '</span>';
26815 } elseif (preg_match("/[" . $this->scriptToLanguage->getLanguageDelimiters('persian') . "]/u", $s)) {
26816 $o .= '<span lang="fa" class="lang_fa">' . $s . '</span>';
26817 } elseif ($this->baseScript != Ucdn::SCRIPT_ARABIC && $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch])) {
26818 $o .= '<span lang="' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '" class="lang_' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '">' . $s . '</span>';
26819 } else {
26820 // Just output chars
26821 $o .= $s;
26822 }
26823 } elseif ($scriptblocks[$sch] > 0 && $scriptblocks[$sch] != $this->baseScript && $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch])) { // Identify Script block if not Basescript, and mark up as language
26824 // Encase in <span>
26825 $o .= '<span lang="' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '" class="lang_' . $this->scriptToLanguage->getLanguageByScript($scriptblocks[$sch]) . '">';
26826 $o .= $s;
26827 $o .= '</span>';
26828 } else {
26829 // Just output chars
26830 $o .= $s;
26831 }
26832 }
26833 }
26834
26835 $a[$i] = $o;
26836 } else {
26837 $a[$i] = '<' . $e . '>';
26838 }
26839 }
26840
26841 $n = implode('', $a);
26842
26843 return $n;
26844 }
26845
26846 /* -- COLUMNS -- */
26850 function columnAdjustAdd($type, $k, $xadj, $yadj, $a, $b, $c = 0, $d = 0, $e = 0, $f = 0)
26851 {
26852 if ($type === 'Td') { // xpos,ypos
26853
26854 $a += ($xadj * $k);
26855 $b -= ($yadj * $k);
26856
26857 return 'BT ' . sprintf('%.3F %.3F', $a, $b) . ' Td';
26858
26859 } elseif ($type === 're') { // xpos,ypos,width,height
26860
26861 $a += ($xadj * $k);
26862 $b -= ($yadj * $k);
26863
26864 return sprintf('%.3F %.3F %.3F %.3F', $a, $b, $c, $d) . ' re';
26865
26866 } elseif ($type === 'l') { // xpos,ypos,x2pos,y2pos
26867
26868 $a += ($xadj * $k);
26869 $b -= ($yadj * $k);
26870
26871 return sprintf('%.3F %.3F l', $a, $b);
26872
26873 } elseif ($type === 'img') { // width,height,xpos,ypos
26874
26875 $c += ($xadj * $k);
26876 $d -= ($yadj * $k);
26877
26878 return sprintf('q %.3F 0 0 %.3F %.3F %.3F', $a, $b, $c, $d) . ' cm /' . $e;
26879
26880 } elseif ($type === 'draw') { // xpos,ypos
26881
26882 $a += ($xadj * $k);
26883 $b -= ($yadj * $k);
26884
26885 return sprintf('%.3F %.3F m', $a, $b);
26886
26887 } elseif ($type === 'bezier') { // xpos,ypos,x2pos,y2pos,x3pos,y3pos
26888
26889 $a += ($xadj * $k);
26890 $b -= ($yadj * $k);
26891 $c += ($xadj * $k);
26892 $d -= ($yadj * $k);
26893 $e += ($xadj * $k);
26894 $f -= ($yadj * $k);
26895
26896 return sprintf('%.3F %.3F %.3F %.3F %.3F %.3F', $a, $b, $c, $d, $e, $f) . ' c';
26897 }
26898 }
26899
26900 /* -- END COLUMNS -- */
26901
26902 // mPDF 5.7.3 TRANSFORMS
26903 function ConvertAngle($s, $makepositive = true)
26904 {
26905 if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i', $s, $m)) {
26906
26907 $angle = $m[1] + 0;
26908
26909 if (strtolower($m[2]) == 'deg') {
26910 $angle = $angle;
26911 } elseif (strtolower($m[2]) == 'grad') {
26912 $angle *= (360 / 400);
26913 } elseif (strtolower($m[2]) == 'rad') {
26914 $angle = rad2deg($angle);
26915 }
26916
26917 while ($angle >= 360) {
26918 $angle -= 360;
26919 }
26920
26921 while ($angle <= -360) {
26922 $angle += 360;
26923 }
26924
26925 if ($makepositive) { // always returns an angle between 0 and 360deg
26926 if ($angle < 0) {
26927 $angle += 360;
26928 }
26929 }
26930
26931 } else {
26932 $angle = $s + 0;
26933 }
26934
26935 return $angle;
26936 }
26937
26939 {
26940 // supports the most used entity codes (only does ascii safe characters)
26941 $html = str_replace("&lt;", "<", $html);
26942 $html = str_replace("&gt;", ">", $html);
26943
26944 $html = str_replace("&apos;", "'", $html);
26945 $html = str_replace("&quot;", '"', $html);
26946 $html = str_replace("&amp;", "&", $html);
26947
26948 return $html;
26949 }
26950
26951 function AdjustHTML($html, $tabSpaces = 8)
26952 {
26953 $limit = ini_get('pcre.backtrack_limit');
26954
26955 if (0 >= (int) $limit) {
26956 throw new \Mpdf\MpdfException(sprintf(
26957 'mPDF will not process HTML with disabled pcre.backtrack_limit to prevent unexpected behaviours, please set a positive backtrack limit.',
26958 $limit
26959 ));
26960 }
26961
26962 if (strlen($html) > (int) $limit) {
26963 throw new \Mpdf\MpdfException(sprintf(
26964 'The HTML code size is larger than pcre.backtrack_limit %d. You should use WriteHTML() with smaller string lengths.',
26965 $limit
26966 ));
26967 }
26968
26969 preg_match_all("/(<annotation.*?>)/si", $html, $m);
26970 if (count($m[1])) {
26971 for ($i = 0; $i < count($m[1]); $i++) {
26972 $sub = preg_replace("/\n/si", "\xbb\xa4\xac", $m[1][$i]);
26973 $html = preg_replace('/' . preg_quote($m[1][$i], '/') . '/si', $sub, $html);
26974 }
26975 }
26976
26977 preg_match_all("/(<svg.*?<\/svg>)/si", $html, $svgi);
26978 if (count($svgi[0])) {
26979 for ($i = 0; $i < count($svgi[0]); $i++) {
26980 $file = $this->cache->write('/_tempSVG' . uniqid(random_int(1, 100000), true) . '_' . $i . '.svg', $svgi[0][$i]);
26981 $html = str_replace($svgi[0][$i], '<img src="' . $file . '" />', $html);
26982 }
26983 }
26984
26985 // Remove javascript code from HTML (should not appear in the PDF file)
26986 $html = preg_replace('/<script.*?<\/script>/is', '', $html);
26987
26988 // Remove special comments
26989 $html = preg_replace('/<!--mpdf/i', '', $html);
26990 $html = preg_replace('/mpdf-->/i', '', $html);
26991
26992 // Remove comments from HTML (should not appear in the PDF file)
26993 $html = preg_replace('/<!--.*?-->/s', '', $html);
26994
26995 $html = preg_replace('/\f/', '', $html); // replace formfeed by nothing
26996 $html = preg_replace('/\r/', '', $html); // replace carriage return by nothing
26997
26998 // Well formed XHTML end tags
26999 $html = preg_replace('/<(br|hr)>/i', "<\\1 />", $html); // mPDF 6
27000 $html = preg_replace('/<(br|hr)\/>/i', "<\\1 />", $html);
27001
27002 // Get rid of empty <thead></thead> etc
27003 $html = preg_replace('/<tr>\s*<\/tr>/i', '', $html);
27004 $html = preg_replace('/<thead>\s*<\/thead>/i', '', $html);
27005 $html = preg_replace('/<tfoot>\s*<\/tfoot>/i', '', $html);
27006 $html = preg_replace('/<table[^>]*>\s*<\/table>/i', '', $html);
27007
27008 // Remove spaces at end of table cells
27009 $html = preg_replace("/[ \n\r]+<\/t(d|h)/", '</t\\1', $html);
27010
27011 $html = preg_replace("/[ ]*<dottab\s*[\/]*>[ ]*/", '<dottab />', $html);
27012
27013 // Concatenates any Substitute characters from symbols/dingbats
27014 $html = str_replace('</tts><tts>', '|', $html);
27015 $html = str_replace('</ttz><ttz>', '|', $html);
27016 $html = str_replace('</tta><tta>', '|', $html);
27017
27018 $html = preg_replace('/<br \/>\s*/is', "<br />", $html);
27019
27020 $html = preg_replace('/<wbr[ \/]*>\s*/is', "&#173;", $html);
27021
27022 // Preserve '\n's in content between the tags <pre> and </pre>
27023 if (preg_match('/<pre/', $html)) {
27024
27025 $html_a = preg_split('/(<\/?pre[^>]*>)/', $html, -1, 2);
27026 $h = [];
27027 $c = 0;
27028
27029 foreach ($html_a as $s) {
27030 if ($c > 1 && preg_match('/^<\/pre/i', $s)) {
27031 $c--;
27032 $s = preg_replace('/<\/pre/i', '</innerpre', $s);
27033 } elseif ($c > 0 && preg_match('/^<pre/i', $s)) {
27034 $c++;
27035 $s = preg_replace('/<pre/i', '<innerpre', $s);
27036 } elseif (preg_match('/^<pre/i', $s)) {
27037 $c++;
27038 } elseif (preg_match('/^<\/pre/i', $s)) {
27039 $c--;
27040 }
27041 array_push($h, $s);
27042 }
27043
27044 $html = implode('', $h);
27045 }
27046
27047 $thereispre = preg_match_all('#<pre(.*?)>(.*?)</pre>#si', $html, $temp);
27048
27049 // Preserve '\n's in content between the tags <textarea> and </textarea>
27050 $thereistextarea = preg_match_all('#<textarea(.*?)>(.*?)</textarea>#si', $html, $temp2);
27051 $html = preg_replace('/[\n]/', ' ', $html); // replace linefeed by spaces
27052 $html = preg_replace('/[\t]/', ' ', $html); // replace tabs by spaces
27053
27054 // Converts < to &lt; when not a tag
27055 $html = preg_replace('/<([^!\/a-zA-Z_:])/i', '&lt;\\1', $html); // mPDF 5.7.3
27056 $html = preg_replace("/[ ]+/", ' ', $html);
27057
27058 $html = preg_replace('/\/li>\s+<\/(u|o)l/i', '/li></\\1l', $html);
27059 $html = preg_replace('/\/(u|o)l>\s+<\/li/i', '/\\1l></li', $html);
27060 $html = preg_replace('/\/li>\s+<\/(u|o)l/i', '/li></\\1l', $html);
27061 $html = preg_replace('/\/li>\s+<li/i', '/li><li', $html);
27062 $html = preg_replace('/<(u|o)l([^>]*)>[ ]+/i', '<\\1l\\2>', $html);
27063 $html = preg_replace('/[ ]+<(u|o)l/i', '<\\1l', $html);
27064
27065 // Make self closing tabs valid XHTML
27066 // Tags which are self-closing: 1) Replaceable and 2) Non-replaced items
27067 $selftabs = 'input|hr|img|br|barcode|dottab';
27068 $selftabs2 = 'indexentry|indexinsert|bookmark|watermarktext|watermarkimage|column_break|columnbreak|newcolumn|newpage|page_break|pagebreak|formfeed|columns|toc|tocpagebreak|setpageheader|setpagefooter|sethtmlpageheader|sethtmlpagefooter|annotation';
27069
27070 // Fix self-closing tags which don't close themselves
27071 $html = preg_replace('/(<(' . $selftabs . '|' . $selftabs2 . ')[^>\/]*)>/i', '\\1 />', $html);
27072
27073 // Fix self-closing tags that don't include a space between the tag name and the closing slash
27074 $html = preg_replace('/(<(' . $selftabs . '|' . $selftabs2 . '))\/>/i', '\\1 />', $html);
27075
27076 $iterator = 0;
27077 while ($thereispre) { // Recover <pre attributes>content</pre>
27078 $temp[2][$iterator] = preg_replace('/<([^!\/a-zA-Z_:])/', '&lt;\\1', $temp[2][$iterator]); // mPDF 5.7.2 // mPDF 5.7.3
27079
27080 $temp[2][$iterator] = preg_replace_callback("/^([^\n\t]*?)\t/m", [$this, 'tabs2spaces_callback'], $temp[2][$iterator]); // mPDF 5.7+
27081 $temp[2][$iterator] = preg_replace('/\t/', str_repeat(" ", $tabSpaces), $temp[2][$iterator]);
27082
27083 $temp[2][$iterator] = preg_replace('/\n/', "<br />", $temp[2][$iterator]);
27084 $temp[2][$iterator] = str_replace('\\', "\\\\", $temp[2][$iterator]);
27085 // $html = preg_replace('#<pre(.*?)>(.*?)</pre>#si','<erp'.$temp[1][$iterator].'>'.$temp[2][$iterator].'</erp>',$html,1);
27086 $html = preg_replace('#<pre(.*?)>(.*?)</pre>#si', '<erp' . $temp[1][$iterator] . '>' . str_replace('$', '\$', $temp[2][$iterator]) . '</erp>', $html, 1); // mPDF 5.7+
27087 $thereispre--;
27088 $iterator++;
27089 }
27090
27091 $iterator = 0;
27092 while ($thereistextarea) { // Recover <textarea attributes>content</textarea>
27093 $temp2[2][$iterator] = preg_replace('/\t/', str_repeat(" ", $tabSpaces), $temp2[2][$iterator]);
27094 $temp2[2][$iterator] = str_replace('\\', "\\\\", $temp2[2][$iterator]);
27095 $html = preg_replace('#<textarea(.*?)>(.*?)</textarea>#si', '<aeratxet' . $temp2[1][$iterator] . '>' . trim($temp2[2][$iterator]) . '</aeratxet>', $html, 1);
27096 $thereistextarea--;
27097 $iterator++;
27098 }
27099
27100 // Restore original tag names
27101 $html = str_replace("<erp", "<pre", $html);
27102 $html = str_replace("</erp>", "</pre>", $html);
27103 $html = str_replace("<aeratxet", "<textarea", $html);
27104 $html = str_replace("</aeratxet>", "</textarea>", $html);
27105 $html = str_replace("</innerpre", "</pre", $html);
27106 $html = str_replace("<innerpre", "<pre", $html);
27107
27108 $html = preg_replace('/<textarea([^>]*)><\/textarea>/si', '<textarea\\1> </textarea>', $html);
27109 $html = preg_replace('/(<table[^>]*>)\s*(<caption)(.*?<\/caption>)(.*?<\/table>)/si', '\\2 position="top"\\3\\1\\4\\2 position="bottom"\\3', $html); // *TABLES*
27110 $html = preg_replace('/<(h[1-6])([^>]*)(>(?:(?!h[1-6]).)*?<\/\\1>\s*<table)/si', '<\\1\\2 keep-with-table="1"\\3', $html); // *TABLES*
27111 $html = preg_replace("/\xbb\xa4\xac/", "\n", $html);
27112
27113 // Fixes <p>&#8377</p> which browser copes with even though it is wrong!
27114 $html = preg_replace("/(&#[x]{0,1}[0-9a-f]{1,5})</i", "\\1;<", $html);
27115
27116 return $html;
27117 }
27118
27119 // mPDF 5.7+
27120 function tabs2spaces_callback($matches)
27121 {
27122 return (stripslashes($matches[1]) . str_repeat(' ', $this->tabSpaces - (mb_strlen(stripslashes($matches[1])) % $this->tabSpaces)));
27123 }
27124
27125 // mPDF 5.7+
27126 function date_callback($matches)
27127 {
27128 return date($matches[1]);
27129 }
27130
27131 // ========== OVERWRITE SEARCH STRING IN A PDF FILE ================
27132 function OverWrite($file_in, $search, $replacement, $dest = Destination::DOWNLOAD, $file_out = "mpdf")
27133 {
27134 $pdf = file_get_contents($file_in);
27135
27136 if (!is_array($search)) {
27137 $x = $search;
27138 $search = [$x];
27139 }
27140 if (!is_array($replacement)) {
27141 $x = $replacement;
27142 $replacement = [$x]; // mPDF 5.7.4
27143 }
27144
27145 if (!$this->onlyCoreFonts && !$this->usingCoreFont) {
27146 foreach ($search as $k => $val) {
27147 $search[$k] = $this->writer->utf8ToUtf16BigEndian($search[$k], false);
27148 $search[$k] = $this->writer->escape($search[$k]);
27149 $replacement[$k] = $this->writer->utf8ToUtf16BigEndian($replacement[$k], false);
27150 $replacement[$k] = $this->writer->escape($replacement[$k]);
27151 }
27152 } else {
27153 foreach ($replacement as $k => $val) {
27154 $replacement[$k] = mb_convert_encoding($replacement[$k], $this->mb_enc, 'utf-8');
27155 $replacement[$k] = $this->writer->escape($replacement[$k]);
27156 }
27157 }
27158
27159 // Get xref into array
27160 $xref = [];
27161 preg_match("/xref\n0 (\d+)\n(.*?)\ntrailer/s", $pdf, $m);
27162 $xref_objid = $m[1];
27163 preg_match_all('/(\d{10}) (\d{5}) (f|n)/', $m[2], $x);
27164 for ($i = 0; $i < count($x[0]); $i++) {
27165 $xref[] = [intval($x[1][$i]), $x[2][$i], $x[3][$i]];
27166 }
27167
27168 $changes = [];
27169 preg_match("/<<\s*\/Type\s*\/Pages\s*\/Kids\s*\[(.*?)\]\s*\/Count/s", $pdf, $m);
27170 preg_match_all("/(\d+) 0 R /s", $m[1], $o);
27171 $objlist = $o[1];
27172
27173 foreach ($objlist as $obj) {
27174 if ($this->compress) {
27175 preg_match("/" . ($obj + 1) . " 0 obj\n<<\s*\/Filter\s*\/FlateDecode\s*\/Length (\d+)>>\nstream\n(.*?)\nendstream\n/s", $pdf, $m);
27176 } else {
27177 preg_match("/" . ($obj + 1) . " 0 obj\n<<\s*\/Length (\d+)>>\nstream\n(.*?)\nendstream\n/s", $pdf, $m);
27178 }
27179
27180 $s = $m[2];
27181 if (!$s) {
27182 continue;
27183 }
27184
27185 $oldlen = $m[1];
27186
27187 if ($this->encrypted) {
27188 $s = $this->protection->rc4($this->protection->objectKey($obj + 1), $s);
27189 }
27190
27191 if ($this->compress) {
27192 $s = gzuncompress($s);
27193 }
27194
27195 foreach ($search as $k => $val) {
27196 $s = str_replace($search[$k], $replacement[$k], $s);
27197 }
27198
27199 if ($this->compress) {
27200 $s = gzcompress($s);
27201 }
27202
27203 if ($this->encrypted) {
27204 $s = $this->protection->rc4($this->protection->objectKey($obj + 1), $s);
27205 }
27206
27207 $newlen = strlen($s);
27208
27209 $changes[($xref[$obj + 1][0])] = ($newlen - $oldlen) + (strlen($newlen) - strlen($oldlen));
27210
27211 if ($this->compress) {
27212 $newstr = ($obj + 1) . " 0 obj\n<</Filter /FlateDecode /Length " . $newlen . ">>\nstream\n" . $s . "\nendstream\n";
27213 } else {
27214 $newstr = ($obj + 1) . " 0 obj\n<</Length " . $newlen . ">>\nstream\n" . $s . "\nendstream\n";
27215 }
27216
27217 $pdf = str_replace($m[0], $newstr, $pdf);
27218 }
27219
27220 // Update xref in PDF
27221 krsort($changes);
27222 $newxref = "xref\n0 " . $xref_objid . "\n";
27223 foreach ($xref as $v) {
27224 foreach ($changes as $ck => $cv) {
27225 if ($v[0] > $ck) {
27226 $v[0] += $cv;
27227 }
27228 }
27229 $newxref .= sprintf('%010d', $v[0]) . ' ' . $v[1] . ' ' . $v[2] . " \n";
27230 }
27231 $newxref .= "trailer";
27232 $pdf = preg_replace("/xref\n0 \d+\n.*?\ntrailer/s", $newxref, $pdf);
27233
27234 // Update startxref in PDF
27235 preg_match("/startxref\n(\d+)\n%%EOF/s", $pdf, $m);
27236 $startxref = $m[1];
27237 $startxref += array_sum($changes);
27238 $pdf = preg_replace("/startxref\n(\d+)\n%%EOF/s", "startxref\n" . $startxref . "\n%%EOF", $pdf);
27239
27240 // OUTPUT
27241 switch ($dest) {
27243 if (isset($_SERVER['SERVER_NAME'])) {
27244 // We send to a browser
27245 header('Content-Type: application/pdf');
27246 header('Content-Length: ' . strlen($pdf));
27247 header('Content-disposition: inline; filename=' . $file_out);
27248 }
27249
27250 echo $pdf;
27251
27252 break;
27253
27254 case Destination::FILE:
27255 if (!$file_out) {
27256 $file_out = 'mpdf.pdf';
27257 }
27258
27259 $f = fopen($file_out, 'wb');
27260
27261 if (!$f) {
27262 throw new \Mpdf\MpdfException('Unable to create output file: ' . $file_out);
27263 }
27264
27265 fwrite($f, $pdf, strlen($pdf));
27266
27267 fclose($f);
27268
27269 break;
27270
27272 return $pdf;
27273
27274 case Destination::DOWNLOAD: // Download file
27275 default:
27276 if (isset($_SERVER['HTTP_USER_AGENT']) and strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
27277 header('Content-Type: application/force-download');
27278 } else {
27279 header('Content-Type: application/octet-stream');
27280 }
27281
27282 header('Content-Length: ' . strlen($pdf));
27283 header('Content-disposition: attachment; filename=' . $file_out);
27284
27285 echo $pdf;
27286
27287 break;
27288 }
27289 }
27290
27291
27292 function Thumbnail($file, $npr = 3, $spacing = 10)
27293 {
27294 // $npr = number per row
27295 $w = (($this->pgwidth + $spacing) / $npr) - $spacing;
27296 $oldlinewidth = $this->LineWidth;
27297 $this->SetLineWidth(0.02);
27298 $this->SetDColor($this->colorConverter->convert(0, $this->PDFAXwarnings));
27299 $h = 0;
27300 $maxh = 0;
27301 $x = $_x = $this->lMargin;
27302 $_y = $this->tMargin;
27303
27304 if ($this->y == 0) {
27305 $y = $_y;
27306 } else {
27307 $y = $this->y;
27308 }
27309
27310 $pagecount = $this->setSourceFile($file);
27311
27312 for ($n = 1; $n <= $pagecount; $n++) {
27313 $tplidx = $this->importPage($n);
27314 $size = $this->useTemplate($tplidx, $x, $y, $w);
27315 $this->Rect($x, $y, $size['width'], $size['height']);
27316 $h = max($h, $size['height']);
27317 $maxh = max($h, $maxh);
27318
27319 if ($n % $npr == 0) {
27320 if (($y + $h + $spacing + $maxh) > $this->PageBreakTrigger && $n != $pagecount) {
27321 $this->AddPage();
27322 $x = $_x;
27323 $y = $_y;
27324 } else {
27325 $y += $h + $spacing;
27326 $x = $_x;
27327 $h = 0;
27328 }
27329 } else {
27330 $x += $w + $spacing;
27331 }
27332 }
27333 $this->SetLineWidth($oldlinewidth);
27334 }
27335
27336 function SetPageTemplate($tplidx = '')
27337 {
27338 if (!isset($this->importedPages[$tplidx])) {
27339 $this->pageTemplate = '';
27340 return false;
27341 }
27342 $this->pageTemplate = $tplidx;
27343 }
27344
27345 function SetDocTemplate($file = '', $continue = 0, $continue2pages = 0)
27346 {
27347 $this->docTemplate = $file;
27348 $this->docTemplateContinue = $continue;
27349 $this->docTemplateContinue2pages = $continue2pages;
27350
27351 if ($this->docTemplateContinue2pages) { // Enable continue when continue2pages is set
27352 $this->docTemplateContinue = $this->docTemplateContinue2pages;
27353 }
27354 }
27355
27356 /* -- END IMPORTS -- */
27357
27358 // JAVASCRIPT
27359 function _set_object_javascript($string)
27360 {
27361 $this->writer->object();
27362 $this->writer->write('<<');
27363 $this->writer->write('/S /JavaScript ');
27364 $this->writer->write('/JS ' . $this->writer->string($string));
27365 $this->writer->write('>>');
27366 $this->writer->write('endobj');
27367 }
27368
27369 function SetJS($script)
27370 {
27371 $this->js = $script;
27372 }
27373
27381 public function toFloat($num)
27382 {
27383 $dotPos = strrpos($num, '.');
27384 $commaPos = strrpos($num, ',');
27385 $sep = (($dotPos > $commaPos) && $dotPos) ? $dotPos : ((($commaPos > $dotPos) && $commaPos) ? $commaPos : false);
27386
27387 if (!$sep) {
27388 return floatval(preg_replace('/[^0-9]/', '', $num));
27389 }
27390
27391 return floatval(
27392 preg_replace('/[^0-9]/', '', substr($num, 0, $sep)) . '.' .
27393 preg_replace('/[^0-9]/', '', substr($num, $sep+1, strlen($num)))
27394 );
27395 }
27396
27397 public function getFontDescriptor()
27398 {
27399 return $this->fontDescriptor;
27400 }
27401
27405 public function _out($s)
27406 {
27407 $this->writer->write($s);
27408 }
27409
27417 protected function aliasReplace($html, $PAGENO, $NbPgGp, $NbPg)
27418 {
27419 // Replaces for header and footer
27420 $html = str_replace('{PAGENO}', $PAGENO, $html);
27421 $html = str_replace($this->aliasNbPgGp, $NbPgGp, $html); // {nbpg}
27422 $html = str_replace($this->aliasNbPg, $NbPg, $html); // {nb}
27423
27424 // Replaces for the body
27425 $html = str_replace(mb_convert_encoding('{PAGENO}', 'UTF-16BE', 'UTF-8'), mb_convert_encoding($PAGENO, 'UTF-16BE', 'UTF-8'), $html);
27426 $html = str_replace(mb_convert_encoding($this->aliasNbPgGp, 'UTF-16BE', 'UTF-8'), mb_convert_encoding($NbPgGp, 'UTF-16BE', 'UTF-8'), $html); // {nbpg}
27427 $html = str_replace(mb_convert_encoding($this->aliasNbPg, 'UTF-16BE', 'UTF-8'), mb_convert_encoding($NbPg, 'UTF-16BE', 'UTF-8'), $html); // {nb}
27428
27429 // Date replace
27430 $html = preg_replace_callback('/\{DATE\s+(.*?)\}/', [$this, 'date_callback'], $html); // mPDF 5.7
27431
27432 return $html;
27433 }
27434
27435}
$this Big5_widths
Definition: CJKdata.php:18
$cw
Definition: CJKdata.php:5
$id
inisialisasi variabel yang menampung session value 'id'
Definition: attach_item.php:8
$desc
Definition: ccourier.php:7
$up
Definition: ccourier.php:8
$ut
Definition: ccourier.php:9
$kerninfo
Definition: chelvetica.php:21
const BOTTOM
Definition: Border.php:11
const RIGHT
Definition: Border.php:10
const LEFT
Definition: Border.php:12
const TOP
Definition: Border.php:9
const FD_UNDERLINE
Definition: TextVars.php:9
const FT_UPPERCASE
Definition: TextVars.php:18
const FD_LINETHROUGH
Definition: TextVars.php:10
const FT_LOWERCASE
Definition: TextVars.php:19
const FA_SUBSCRIPT
Definition: TextVars.php:15
const FT_CAPITALIZE
Definition: TextVars.php:20
const FA_SUPERSCRIPT
Definition: TextVars.php:14
const FC_SMALLCAPS
Definition: TextVars.php:24
AdjustHTML($html, $tabSpaces=8)
Definition: Mpdf.php:26951
SetLineCap($mode=2)
Definition: Mpdf.php:9321
SetMargins($left, $right, $top)
Definition: Mpdf.php:1708
_out($s)
Definition: Mpdf.php:27405
$arabPrevLink
Definition: Mpdf.php:389
_tableHeight(&$table)
Definition: Mpdf.php:20305
$SJIS_widths
Definition: Mpdf.php:484
$tdbegin
Definition: Mpdf.php:541
$original_default_font
Definition: Mpdf.php:625
AcceptPageBreak()
Definition: Mpdf.php:24237
issetBorder($var, $flag)
Definition: Mpdf.php:21294
Bookmark($txt, $level=0, $y=0)
Definition: Mpdf.php:23328
printcellbuffer()
Definition: Mpdf.php:24922
$SHYleftmin
Definition: Mpdf.php:119
AddSpotColorsFromFile($file)
Definition: Mpdf.php:3330
SetDrawColor($r, $g=-1, $b=-1, $col4=-1, $return=false)
Definition: Mpdf.php:3426
$incrementFPR4
Definition: Mpdf.php:116
SetDefaultFont($font)
Definition: Mpdf.php:10908
_setDashBorder($style, $div, $cp, $side)
Definition: Mpdf.php:16597
UTF8StringToArray($str, $addSubset=true)
Definition: Mpdf.php:10678
_computeLineheight($lh, $fs='')
Definition: Mpdf.php:11020
$watermarkImageAlpha
Definition: Mpdf.php:137
$associatedFiles
Definition: Mpdf.php:819
$pagenumSuffix
Definition: Mpdf.php:127
SetAutoPageBreak($auto, $margin=0)
Definition: Mpdf.php:1766
$percentSubset
Definition: Mpdf.php:90
$default_lang
Definition: Mpdf.php:375
$ktAnnots
Definition: Mpdf.php:398
$orig_bMargin
Definition: Mpdf.php:448
SetHTMLFooterByName($name, $side='O')
Definition: Mpdf.php:12702
$margin_bottom_collapse
Definition: Mpdf.php:622
$tbrotForms
Definition: Mpdf.php:403
MultiCell( $w, $h, $txt, $border=0, $align='', $fill=0, $link='', $directionality='ltr', $encoded=false, $OTLdata=false, $maxrows=false)
Definition: Mpdf.php:5833
$kwt_Annots
Definition: Mpdf.php:400
$curlExecutionTimeout
Definition: Mpdf.php:677
SetLineJoin($mode=0)
Definition: Mpdf.php:9312
$incrementFPR2
Definition: Mpdf.php:114
$pageTemplate
Definition: Mpdf.php:379
SetTextColor($r, $g=-1, $b=-1, $col4=-1, $return=false)
Definition: Mpdf.php:3456
RestartDocTemplate()
Definition: Mpdf.php:11724
SubstituteHiEntities($html)
Definition: Mpdf.php:25990
Open()
Definition: Mpdf.php:1967
$pregCURSchars
Definition: Mpdf.php:198
$keepColumns
Definition: Mpdf.php:144
ConvertAngle($s, $makepositive=true)
Definition: Mpdf.php:26903
printtablebuffer()
Definition: Mpdf.php:24969
$tableMinSizePriority
Definition: Mpdf.php:94
GetCharWidthCore($c)
Definition: Mpdf.php:3505
$textbuffer
Definition: Mpdf.php:571
$normalLineheight
Definition: Mpdf.php:112
$pgwidth
Definition: Mpdf.php:534
$anchor2Bookmark
Definition: Mpdf.php:179
SetStylesArray($arr)
Definition: Mpdf.php:18993
$fixedPosBlock
Definition: Mpdf.php:310
$fontlist
Definition: Mpdf.php:535
$thead_textalign_default
Definition: Mpdf.php:636
markScriptToLang($html)
Definition: Mpdf.php:26724
$default_font_size
Definition: Mpdf.php:623
$sans_fonts
Definition: Mpdf.php:467
$orig_tMargin
Definition: Mpdf.php:449
_tableWrite(&$table, $split=false, $startrow=0, $startcol=0, $splitpg=0, $rety=0)
Definition: Mpdf.php:21869
$arabNextLink
Definition: Mpdf.php:390
$saveHTMLFooter_height
Definition: Mpdf.php:417
$thead_font_smCaps
Definition: Mpdf.php:634
$defaultSubsFont
Definition: Mpdf.php:470
$kwt_saved
Definition: Mpdf.php:438
$inFixedPosBlock
Definition: Mpdf.php:309
SetPagedMediaCSS($name, $first, $oddEven)
Definition: Mpdf.php:14908
$cell_border_dominance_L
Definition: Mpdf.php:332
$basepathIsLocal
Definition: Mpdf.php:428
$header_line_spacing
Definition: Mpdf.php:193
$InlineBDFctr
Definition: Mpdf.php:396
$dash_on
Definition: Mpdf.php:568
$mono_fonts
Definition: Mpdf.php:469
$blockjustfinished
Definition: Mpdf.php:446
$FillColor
Definition: Mpdf.php:799
$watermarkText
Definition: Mpdf.php:201
$currentfontfamily
Definition: Mpdf.php:573
$offsets
Definition: Mpdf.php:746
$tableBackgrounds
Definition: Mpdf.php:263
$tablethead
Definition: Mpdf.php:631
$HTMLheaderPageAnnots
Definition: Mpdf.php:462
$LayoutMode
Definition: Mpdf.php:810
Rect($x, $y, $w, $h, $style='')
Definition: Mpdf.php:3794
$MarginCorrection
Definition: Mpdf.php:655
PrintTableBackgrounds($adjustmenty=0)
Definition: Mpdf.php:2578
$textshadow
Definition: Mpdf.php:242
$lastblocklevelchange
Definition: Mpdf.php:329
$minwSpacing
Definition: Mpdf.php:252
SetJS($script)
Definition: Mpdf.php:27369
$packTableData
Definition: Mpdf.php:100
$blockContext
Definition: Mpdf.php:341
$PageNumSubstitutions
Definition: Mpdf.php:440
SetDocTemplate($file='', $continue=0, $continue2pages=0)
Definition: Mpdf.php:27345
$visibility
Definition: Mpdf.php:248
$docTemplateStart
Definition: Mpdf.php:320
$cellBorderBuffer
Definition: Mpdf.php:415
$defaultheaderfontsize
Definition: Mpdf.php:187
$nestedtablejustfinished
Definition: Mpdf.php:330
MovePages($target_page, $start_page, $end_page=-1)
Definition: Mpdf.php:23512
$tableLevel
Definition: Mpdf.php:411
SetTopMargin($margin)
Definition: Mpdf.php:1754
SetDash($black=false, $white=false)
Definition: Mpdf.php:9330
$curlAllowUnsafeSslRequests
Definition: Mpdf.php:704
setCSS($arrayaux, $type='', $tag='')
Definition: Mpdf.php:18117
$spotColors
Definition: Mpdf.php:258
_getListMarkerWidth(&$currblk, &$a, &$i)
Definition: Mpdf.php:15574
applyGPOSpdf($txt, $aix, $x, $y, $OTLdata, $textvar=0)
Definition: Mpdf.php:5418
$entsearch
Definition: Mpdf.php:517
$persianGlyphs
Definition: Mpdf.php:386
$fullImageHeight
Definition: Mpdf.php:307
$SHYlang
Definition: Mpdf.php:118
$listitem
Definition: Mpdf.php:562
$FontStyle
Definition: Mpdf.php:794
$max_colH_correction
Definition: Mpdf.php:173
AddUHCFont()
Definition: Mpdf.php:10874
SetColumns($NbCol, $vAlign='', $gap=5)
Definition: Mpdf.php:24287
$annotSize
Definition: Mpdf.php:140
$textvar
Definition: Mpdf.php:222
$watermarkImgAlpha
Definition: Mpdf.php:272
SetProtection($permissions=[], $user_pass='', $owner_pass=null, $length=40)
Definition: Mpdf.php:23321
TableHeaderFooter($content='', $tablestartpage='', $tablestartcolumn='', $horf='H', $level=0, $firstSpread=true, $finalSpread=true)
Definition: Mpdf.php:11744
$forcePortraitHeaders
Definition: Mpdf.php:160
$substitute
Definition: Mpdf.php:516
_getPrevChar($contentctr, $charctr, $content)
Definition: Mpdf.php:7713
$cropMarkMargin
Definition: Mpdf.php:68
SubstituteCharsNonCore(&$writehtml_a, &$writehtml_i, &$writehtml_e)
Definition: Mpdf.php:25592
_setBorderLine($b, $k=1)
Definition: Mpdf.php:16611
$defaultTableAlign
Definition: Mpdf.php:630
$colvAlign
Definition: Mpdf.php:513
DefHeaderByName($name, $arr)
Definition: Mpdf.php:12636
$jSmaxWordLast
Definition: Mpdf.php:171
$open_layer_pane
Definition: Mpdf.php:234
_resizeBackgroundImage($imw, $imh, $cw, $ch, $resize, $repx, $repy, $pba=[], $size=[])
Definition: Mpdf.php:2053
$TextColor
Definition: Mpdf.php:800
_Arc($x1, $y1, $x2, $y2, $x3, $y3)
Definition: Mpdf.php:10656
$tbrot_maxh
Definition: Mpdf.php:592
$noImageFile
Definition: Mpdf.php:292
SetAdditionalXmpRdf($s)
Definition: Mpdf.php:1866
Footer()
Definition: Mpdf.php:13026
$BMoutlines
Definition: Mpdf.php:493
$BMPonly
Definition: Mpdf.php:92
_tableGetHeight(&$table, $i, $j)
Definition: Mpdf.php:20695
$DefrMargin
Definition: Mpdf.php:776
Close()
Definition: Mpdf.php:1980
fixLineheight($v)
Definition: Mpdf.php:10976
_tableWidth(&$table)
Definition: Mpdf.php:20003
$aliasNbPg
Definition: Mpdf.php:822
$tfoot_font_style
Definition: Mpdf.php:639
$mirrorMargins
Definition: Mpdf.php:200
$MetadataRoot
Definition: Mpdf.php:275
$objectbuffer
Definition: Mpdf.php:587
$fontsizes
Definition: Mpdf.php:210
$currentfontstyle
Definition: Mpdf.php:572
$borderstyles
Definition: Mpdf.php:444
SetXY($x, $y)
Definition: Mpdf.php:9471
_getStyledNumber($ppgno, $type, $listmarker=false)
Definition: Mpdf.php:11627
$FontFiles
Definition: Mpdf.php:786
TOC_Entry($txt, $level=0, $toc_id=0)
Definition: Mpdf.php:23465
$shrink_tables_to_fit
Definition: Mpdf.php:180
$pageHTMLheaders
Definition: Mpdf.php:455
$ColWidth
Definition: Mpdf.php:504
SetStyles($str)
Definition: Mpdf.php:19013
$useAdobeCJK
Definition: Mpdf.php:89
$kwt_moved
Definition: Mpdf.php:437
$defTextColor
Definition: Mpdf.php:259
TOCpagebreak($tocfont='', $tocfontsize='', $tocindent='', $TOCusePaging=true, $TOCuseLinking='', $toc_orientation='', $toc_mgl='', $toc_mgr='', $toc_mgt='', $toc_mgb='', $toc_mgh='', $toc_mgf='', $toc_ohname='', $toc_ehname='', $toc_ofname='', $toc_efname='', $toc_ohvalue=0, $toc_ehvalue=0, $toc_ofvalue=0, $toc_efvalue=0, $toc_preHTML='', $toc_postHTML='', $toc_bookmarkText='', $resetpagenum='', $pagenumstyle='', $suppress='', $orientation='', $mgl='', $mgr='', $mgt='', $mgb='', $mgh='', $mgf='', $ohname='', $ehname='', $ofname='', $efname='', $ohvalue=0, $ehvalue=0, $ofvalue=0, $efvalue=0, $toc_id=0, $pagesel='', $toc_pagesel='', $sheetsize='', $toc_sheetsize='', $tocoutdent='')
Definition: Mpdf.php:23444
_saveCellTextBuffer($t, $link='', $intlink='')
Definition: Mpdf.php:15826
$CJKoverflow
Definition: Mpdf.php:240
$cellPaddingL
Definition: Mpdf.php:646
$table_error_report_param
Definition: Mpdf.php:176
$default_lineheight_correction
Definition: Mpdf.php:581
$setAutoTopMargin
Definition: Mpdf.php:107
$ReqFontStyle
Definition: Mpdf.php:304
_setPageSize($format, &$orientation)
Definition: Mpdf.php:1632
SetCol($CurrCol)
Definition: Mpdf.php:24369
$checkCJK
Definition: Mpdf.php:270
printbuffer($arrayaux, $blockstate=0, $is_table=false, $table_draft=false, $cell_dir='')
Definition: Mpdf.php:15881
$justifyB4br
Definition: Mpdf.php:99
$jSmaxCharLast
Definition: Mpdf.php:170
_setClippingPath($clx, $cly, $clw, $clh)
Definition: Mpdf.php:2299
$firstPageBoxHeader
Definition: Mpdf.php:420
$h2bookmarks
Definition: Mpdf.php:51
$InFooter
Definition: Mpdf.php:804
ClearFloats($clear, $blklvl=0)
Definition: Mpdf.php:15278
$n_ocg_print
Definition: Mpdf.php:743
$UHC_widths
Definition: Mpdf.php:485
$currentLang
Definition: Mpdf.php:374
$LineWidth
Definition: Mpdf.php:782
$keep_table_proportions
Definition: Mpdf.php:145
DivLn($h, $level=-3, $move_y=true, $collapsible=false, $state=0)
Definition: Mpdf.php:9374
SetDefaultBodyCSS($prop, $val)
Definition: Mpdf.php:10941
$ignorefollowingspaces
Definition: Mpdf.php:565
$orig_fMargin
Definition: Mpdf.php:453
$writingHTMLheader
Definition: Mpdf.php:351
$InlineProperties
Definition: Mpdf.php:393
$columnAnnots
Definition: Mpdf.php:401
_tableGetWidth(&$table, $i, $j)
Definition: Mpdf.php:20640
$creator
Definition: Mpdf.php:815
_getBorderWidths($bindata)
Definition: Mpdf.php:19455
$CurOrientation
Definition: Mpdf.php:753
$cell_border_dominance_T
Definition: Mpdf.php:334
SetHTMLFooter($footer='', $OE='')
Definition: Mpdf.php:12324
$showWatermarkText
Definition: Mpdf.php:204
SetHeader($Harray=[], $side='', $write=false)
Definition: Mpdf.php:12710
$exposeVersion
Definition: Mpdf.php:829
$writingToC
Definition: Mpdf.php:230
GetCharWidthNonCore($c, $addSubset=true)
Definition: Mpdf.php:3536
$shrink_this_table_to_fit
Definition: Mpdf.php:654
AddSpotColor($name, $c, $m, $y, $k)
Definition: Mpdf.php:3346
$processingFooter
Definition: Mpdf.php:807
SubstituteCharsSIP(&$writehtml_a, &$writehtml_i, &$writehtml_e)
Definition: Mpdf.php:25571
SetAssociatedFiles(array $files)
Definition: Mpdf.php:1861
$tabletfoot
Definition: Mpdf.php:637
$listcounter
Definition: Mpdf.php:559
finishFlowingBlock($endofblock=false, $next='')
Definition: Mpdf.php:6436
AddPageByArray($a)
Definition: Mpdf.php:2788
$PDFAauto
Definition: Mpdf.php:77
$orig_rMargin
Definition: Mpdf.php:451
SetDisplayMode($zoom, $layout='continuous')
Definition: Mpdf.php:1774
$thead_valign_default
Definition: Mpdf.php:635
$HTMLHeader
Definition: Mpdf.php:475
$bufferoutput
Definition: Mpdf.php:479
AddPage( $orientation='', $condition='', $resetpagenum='', $pagenumstyle='', $suppress='', $mgl='', $mgr='', $mgt='', $mgb='', $mgh='', $mgf='', $ohname='', $ehname='', $ofname='', $efname='', $ohvalue=0, $ehvalue=0, $ofvalue=0, $efvalue=0, $pagesel='', $newformat='')
Definition: Mpdf.php:2903
$ColorFlag
Definition: Mpdf.php:801
$table_rotate
Definition: Mpdf.php:590
$autoPageBreak
Definition: Mpdf.php:802
$page_break_after_avoid
Definition: Mpdf.php:621
setBorder(&$var, $flag, $set=true)
Definition: Mpdf.php:21284
$pdf_version
Definition: Mpdf.php:280
$checkSMP
Definition: Mpdf.php:269
$default_available_fonts
Definition: Mpdf.php:377
SetDirectionality($dir='ltr')
Definition: Mpdf.php:10949
$defaultfooterfontsize
Definition: Mpdf.php:190
$watermarkTextAlpha
Definition: Mpdf.php:136
_splitTableGetWidth(&$table, $i, $j)
Definition: Mpdf.php:20665
SetLeftMargin($margin)
Definition: Mpdf.php:1745
$table_keep_together
Definition: Mpdf.php:336
$encrypted
Definition: Mpdf.php:488
$kwt_height
Definition: Mpdf.php:432
lesser_entity_decode($html)
Definition: Mpdf.php:26938
$defaultPageNumStyle
Definition: Mpdf.php:212
DefHTMLHeaderByName($name, $html)
Definition: Mpdf.php:12674
BeginLayer($id)
Definition: Mpdf.php:2757
$cellPaddingT
Definition: Mpdf.php:648
toFloat($num)
Definition: Mpdf.php:27381
Circle($x, $y, $r, $style='S')
Definition: Mpdf.php:25334
_shareHeaderFooterWidth($cl, $cc, $cr)
Definition: Mpdf.php:12510
AddCJKFont($family)
Definition: Mpdf.php:10786
$cMarginR
Definition: Mpdf.php:771
SetTextOutline($params=[])
Definition: Mpdf.php:8818
printcolumnbuffer()
Definition: Mpdf.php:24424
$defFillColor
Definition: Mpdf.php:261
$autoLangToFont
Definition: Mpdf.php:135
date_callback($matches)
Definition: Mpdf.php:27126
$watermarkImgBehind
Definition: Mpdf.php:98
$margBuffer
Definition: Mpdf.php:54
$cMarginB
Definition: Mpdf.php:773
SetPageTemplate($tplidx='')
Definition: Mpdf.php:27336
$shrin_k
Definition: Mpdf.php:653
SetStyle($tag, $enable)
Definition: Mpdf.php:18979
_postForcedPagebreak($pagebreaktype, $startpage, $save_blk, $save_blklvl)
Definition: Mpdf.php:2855
SetAlpha($alpha, $bm='Normal', $return=false, $mode='B')
Definition: Mpdf.php:1888
$enabledtags
Definition: Mpdf.php:578
SetColor($col, $type='')
Definition: Mpdf.php:3356
$FontSizePt
Definition: Mpdf.php:796
WriteFixedPosHTML($html, $x, $y, $w, $h, $overflow='visible', $bounding=[])
Definition: Mpdf.php:13908
$InfoRoot
Definition: Mpdf.php:277
SetFooter($Farray=[], $side='')
Definition: Mpdf.php:12857
_getHtmlHeight($html)
Definition: Mpdf.php:12390
$useSubstitutions
Definition: Mpdf.php:157
$cMarginT
Definition: Mpdf.php:772
$innermostTableLevel
Definition: Mpdf.php:413
$breakpoints
Definition: Mpdf.php:409
$spanbgcolorarray
Definition: Mpdf.php:326
$cellLineStackingShift
Definition: Mpdf.php:556
$extrapagebreak
Definition: Mpdf.php:217
$dotted_on
Definition: Mpdf.php:569
$processingHeader
Definition: Mpdf.php:808
SetTColor($col, $return=false)
Definition: Mpdf.php:3413
_setLineYpos(&$fontsize, &$fontdesc, &$CSSlineheight, $blockYpos=false)
Definition: Mpdf.php:11041
$SHYlanguages
Definition: Mpdf.php:123
$OrientationChanges
Definition: Mpdf.php:754
$columnLinks
Definition: Mpdf.php:512
SetCreator($creator)
Definition: Mpdf.php:1827
$restrictColorSpace
Definition: Mpdf.php:65
$n_ocg_view
Definition: Mpdf.php:744
$associatedFilesRoot
Definition: Mpdf.php:278
$list_indent_default_mpdf
Definition: Mpdf.php:153
_getObjAttr($t)
Definition: Mpdf.php:9074
$allowAnnotationFiles
Definition: Mpdf.php:288
TOCpagebreakByArray($a)
Definition: Mpdf.php:23391
$upperCase
Definition: Mpdf.php:267
$HTMLheaderPageLinks
Definition: Mpdf.php:461
$col_BMoutlines
Definition: Mpdf.php:365
$selectoption
Definition: Mpdf.php:586
GetStringWidth($s, $addSubset=true, $OTLdata=false, $textvar=0, $includeKashida=false)
Definition: Mpdf.php:3606
$kwt_BMoutlines
Definition: Mpdf.php:359
$saveHTMLHeader
Definition: Mpdf.php:458
$orig_hMargin
Definition: Mpdf.php:452
$headerbuffer
Definition: Mpdf.php:328
WriteBarcode2($code, $x='', $y='', $size=1, $height=1, $bgcol=false, $col=false, $btype='IMB', $print_ratio='', $k=1, $quiet_zone_left=null, $quiet_zone_right=null)
Definition: Mpdf.php:26480
$annotOpacity
Definition: Mpdf.php:142
_set_object_javascript($string)
Definition: Mpdf.php:27359
GetFloatDivInfo($blklvl=0, $clear=false)
Definition: Mpdf.php:15310
ReadCharset($html)
Definition: Mpdf.php:18105
$customProperties
Definition: Mpdf.php:817
$pagenumPrefix
Definition: Mpdf.php:126
magic_reverse_dir(&$chunk, $dir, &$chunkOTLdata)
Definition: Mpdf.php:25428
$CJKfollowing
Definition: Mpdf.php:239
SetHTMLHeader($header='', $OE='', $write=false)
Definition: Mpdf.php:12257
$kerning
Definition: Mpdf.php:250
WriteBarcode($code, $showtext=1, $x='', $y='', $size=1, $border=0, $paddingL=1, $paddingR=1, $paddingT=2, $paddingB=2, $height=1, $bgcol=false, $col=false, $btype='ISBN', $supplement='0', $supplement_code='', $k=1)
Definition: Mpdf.php:26100
_preForcedPagebreak($pagebreaktype)
Definition: Mpdf.php:2820
AddBig5Font()
Definition: Mpdf.php:10803
$crossMarkMargin
Definition: Mpdf.php:67
$defaultAlign
Definition: Mpdf.php:627
$firstPageBoxFooter
Definition: Mpdf.php:422
$SHYcharmax
Definition: Mpdf.php:122
$defaultfooterline
Definition: Mpdf.php:192
AddFontDirectory($directory)
Definition: Mpdf.php:3807
TOC( $tocfont='', $tocfontsize=0, $tocindent=0, $resetpagenum='', $pagenumstyle='', $suppress='', $toc_orientation='', $TOCusePaging=true, $TOCuseLinking=false, $toc_id=0, $tocoutdent='')
Definition: Mpdf.php:23362
$allow_html_optional_endtags
Definition: Mpdf.php:182
$smCapsScale
Definition: Mpdf.php:82
$available_unifonts
Definition: Mpdf.php:466
$enc_obj_id
Definition: Mpdf.php:490
SubstituteChars($html)
Definition: Mpdf.php:25554
WriteFlowingBlock($s, $sOTLdata)
Definition: Mpdf.php:7736
$charspacing
Definition: Mpdf.php:661
$entsubstitute
Definition: Mpdf.php:518
Header($content='')
Definition: Mpdf.php:11730
$textparam
Definition: Mpdf.php:583
$repackageTTF
Definition: Mpdf.php:60
$fixedlSpacing
Definition: Mpdf.php:251
writeHTMLHeaders()
Definition: Mpdf.php:12439
$falseBoldWeight
Definition: Mpdf.php:111
PrintPageBackgrounds($adjustmenty=0)
Definition: Mpdf.php:2311
_beginpage( $orientation, $mgl='', $mgr='', $mgt='', $mgb='', $mgh='', $mgf='', $ohname='', $ehname='', $ofname='', $efname='', $ohvalue=0, $ehvalue=0, $ofvalue=0, $efvalue=0, $pagesel='', $newformat='')
Definition: Mpdf.php:10064
$defaultheaderfontstyle
Definition: Mpdf.php:188
$floatmargins
Definition: Mpdf.php:369
UTF8toSubset($str)
Definition: Mpdf.php:10707
$debugfonts
Definition: Mpdf.php:88
$currentfontsize
Definition: Mpdf.php:574
$adjustFontDescLineheight
Definition: Mpdf.php:40
$serif_fonts
Definition: Mpdf.php:468
$CSSselectMedia
Definition: Mpdf.php:158
$jSmaxChar
Definition: Mpdf.php:169
$footer_line_spacing
Definition: Mpdf.php:194
$curlFollowLocation
Definition: Mpdf.php:684
$table_border_css_set
Definition: Mpdf.php:651
Thumbnail($file, $npr=3, $spacing=10)
Definition: Mpdf.php:27292
$bodyBackgroundGradient
Definition: Mpdf.php:347
_setInlineBlockHeights(&$lineBox, &$stackHeight, &$content, &$font, $is_table)
Definition: Mpdf.php:11115
$docTemplateContinue2pages
Definition: Mpdf.php:382
$fontLanguageOverride
Definition: Mpdf.php:223
$pregCJKchars
Definition: Mpdf.php:196
$kwt_toc
Definition: Mpdf.php:360
SetSubject($subject)
Definition: Mpdf.php:1809
transformSkew($angle_x, $angle_y, $x='', $y='', $returnstring=false)
Definition: Mpdf.php:26681
$maxTTFFilesize
Definition: Mpdf.php:91
$cacheCleanupInterval
Definition: Mpdf.php:286
$rMargin
Definition: Mpdf.php:768
$FontFamily
Definition: Mpdf.php:793
$cellLineHeight
Definition: Mpdf.php:554
transformTranslate($t_x, $t_y, $returnstring=false)
Definition: Mpdf.php:26628
purify_utf8_text($txt)
Definition: Mpdf.php:26068
$colsums
Definition: Mpdf.php:244
$list_symbol_size
Definition: Mpdf.php:155
docPageNum($num=0, $extras=false)
Definition: Mpdf.php:11525
$DefOrientation
Definition: Mpdf.php:752
$PageBreakTrigger
Definition: Mpdf.php:803
$margin_footer
Definition: Mpdf.php:656
$InlineBDF
Definition: Mpdf.php:395
$pageDim
Definition: Mpdf.php:407
$col_toc
Definition: Mpdf.php:366
aliasReplace($html, $PAGENO, $NbPgGp, $NbPg)
Definition: Mpdf.php:27417
$writingHTMLfooter
Definition: Mpdf.php:352
$useFixedNormalLineHeight
Definition: Mpdf.php:38
AddSJISFont()
Definition: Mpdf.php:10850
$thead_font_weight
Definition: Mpdf.php:632
$bodyBackgroundImage
Definition: Mpdf.php:348
$tbrot_w
Definition: Mpdf.php:601
$ICCProfile
Definition: Mpdf.php:78
$cropMarkLength
Definition: Mpdf.php:69
$incrementFPR3
Definition: Mpdf.php:115
$tbrot_toc
Definition: Mpdf.php:363
$extraFontSubsets
Definition: Mpdf.php:318
$lastoptionaltag
Definition: Mpdf.php:524
$tbrot_align
Definition: Mpdf.php:594
SetRightMargin($margin)
Definition: Mpdf.php:1760
$printers_info
Definition: Mpdf.php:80
$Big5_widths
Definition: Mpdf.php:482
$OutputIntentRoot
Definition: Mpdf.php:276
AddExtGState($parms)
Definition: Mpdf.php:1917
$nbpgPrefix
Definition: Mpdf.php:129
DeletePages($start_page, $end_page=-1)
Definition: Mpdf.php:23770
$divwidth
Definition: Mpdf.php:548
$baseScript
Definition: Mpdf.php:46
setLogger(LoggerInterface $logger)
Definition: Mpdf.php:1569
Arrow($x1, $y1, $x2, $y2, $headsize=3, $fill='B', $angle=25)
Definition: Mpdf.php:3762
$decimal_offset
Definition: Mpdf.php:235
Link($x, $y, $w, $h, $link)
Definition: Mpdf.php:4323
$title2annots
Definition: Mpdf.php:143
$Reference
Definition: Mpdf.php:498
$pregRTLchars
Definition: Mpdf.php:197
SetFontSize($size, $write=true)
Definition: Mpdf.php:4284
$floatDivs
Definition: Mpdf.php:342
SetLink($link, $y=0, $page=-1)
Definition: Mpdf.php:4311
saveFont()
Definition: Mpdf.php:6339
$tfoot_textalign_default
Definition: Mpdf.php:642
$extgstates
Definition: Mpdf.php:610
$watermarkImage
Definition: Mpdf.php:203
GetFullPath(&$path, $basepath='')
Definition: Mpdf.php:11452
$bgcolorarray
Definition: Mpdf.php:576
$trow_text_rotate
Definition: Mpdf.php:644
_endpage()
Definition: Mpdf.php:10453
$kwt_buffer
Definition: Mpdf.php:435
$bleedMargin
Definition: Mpdf.php:66
SetHTMLHeaderByName($name, $side='O', $write=false)
Definition: Mpdf.php:12694
InsertIndex($usedivletters=1, $useLinking=false, $indexCollationLocale='', $indexCollationGroup='')
Definition: Mpdf.php:24017
SetSubstitutions()
Definition: Mpdf.php:25544
SetX($x)
Definition: Mpdf.php:9450
_transform($tm, $returnstring=false)
Definition: Mpdf.php:26714
$default_font
Definition: Mpdf.php:327
_moveToPrevChar(&$contentctr, &$charctr, $content)
Definition: Mpdf.php:7689
_EllipseArc($x0, $y0, $rx, $ry, $seg=1, $part=false, $start=false)
Definition: Mpdf.php:17750
$enableImports
Definition: Mpdf.php:103
$subArrMB
Definition: Mpdf.php:303
$cell_border_dominance_B
Definition: Mpdf.php:335
WriteText($x, $y, $txt)
Definition: Mpdf.php:4483
$OTLdata
Definition: Mpdf.php:225
$CurrentFont
Definition: Mpdf.php:795
$list_number_suffix
Definition: Mpdf.php:148
border_details($bd)
Definition: Mpdf.php:14800
$setAutoBottomMargin
Definition: Mpdf.php:108
$fontdata
Definition: Mpdf.php:290
$baselineC
Definition: Mpdf.php:294
$spanborddet
Definition: Mpdf.php:246
$current_layer
Definition: Mpdf.php:233
SetDisplayPreferences($preferences)
Definition: Mpdf.php:9345
$cellPaddingR
Definition: Mpdf.php:647
SetKeywords($keywords)
Definition: Mpdf.php:1821
SetLineWidth($width)
Definition: Mpdf.php:3745
$margin_header
Definition: Mpdf.php:657
$allowCJKoverflow
Definition: Mpdf.php:62
AliasNbPageGroups($alias='{nbpg}')
Definition: Mpdf.php:1882
$watermarkAngle
Definition: Mpdf.php:202
SetDefaultFontSize($fontsize)
Definition: Mpdf.php:10932
$showImageErrors
Definition: Mpdf.php:131
_unpackCellBorder($bindata)
Definition: Mpdf.php:19472
$list_auto_mode
Definition: Mpdf.php:150
$baselineS
Definition: Mpdf.php:299
$PageLinks
Definition: Mpdf.php:791
$uniqstr
Definition: Mpdf.php:219
_borderPadding($a, $b, &$px, &$py)
Definition: Mpdf.php:14884
$incrementFPR1
Definition: Mpdf.php:113
$layerDetails
Definition: Mpdf.php:232
ReadMetaTags($html)
Definition: Mpdf.php:18077
$bMargin
Definition: Mpdf.php:769
$GB_widths
Definition: Mpdf.php:483
$originalMbRegexEnc
Definition: Mpdf.php:606
SubstituteCharsMB(&$writehtml_a, &$writehtml_i, &$writehtml_e)
Definition: Mpdf.php:25708
$pageoutput
Definition: Mpdf.php:525
$forcePortraitMargins
Definition: Mpdf.php:161
$listlvl
Definition: Mpdf.php:560
$HTMLHeaderE
Definition: Mpdf.php:477
_packCellBorder($cell)
Definition: Mpdf.php:19441
$wSpacingCSS
Definition: Mpdf.php:254
docPageNumTotal($num=0, $extras=false)
Definition: Mpdf.php:11574
restoreFont(&$saved, $write=true)
Definition: Mpdf.php:6365
$DisplayPreferences
Definition: Mpdf.php:734
PageNo()
Definition: Mpdf.php:3325
$firstPageBoxFooterEven
Definition: Mpdf.php:423
$specialcontent
Definition: Mpdf.php:585
$useActiveForms
Definition: Mpdf.php:58
$SHYrightmin
Definition: Mpdf.php:120
AddCIDFont($family, $style, $name, &$cw, $CMap, $registry, $desc)
Definition: Mpdf.php:10769
_setAutoHeaderHeight(&$htmlh)
Definition: Mpdf.php:10398
$saveHTMLFooter
Definition: Mpdf.php:459
$CJKleading
Definition: Mpdf.php:238
$patterns
Definition: Mpdf.php:344
$baselineO
Definition: Mpdf.php:300
$OutlineRoot
Definition: Mpdf.php:494
_kern($txt, $mode, $aix, $x, $y)
Definition: Mpdf.php:5768
$fixedPosBlockDepth
Definition: Mpdf.php:311
_tableRect($x, $y, $w, $h, $bord=-1, $details=[], $buffer=false, $bSeparate=false, $cort='cell', $tablecorner='', $bsv=0, $bsh=0)
Definition: Mpdf.php:20751
writeHTMLFooters()
Definition: Mpdf.php:12472
$firstPageBoxHeaderEven
Definition: Mpdf.php:421
$cMarginL
Definition: Mpdf.php:770
_dochecks()
Definition: Mpdf.php:9633
SetTitle($title)
Definition: Mpdf.php:1803
$fixedPosBlockBBox
Definition: Mpdf.php:312
DefFooterByName($name, $arr)
Definition: Mpdf.php:12647
PaintImgBorder($objattr, $is_table)
Definition: Mpdf.php:17922
newFlowingBlock($w, $h, $a='', $is_table=false, $blockstate=0, $newblock=true, $blockdir='ltr', $table_draft=false)
Definition: Mpdf.php:6404
$table_error_report
Definition: Mpdf.php:175
$curlTimeout
Definition: Mpdf.php:670
SetFont($family, $style='', $size=0, $write=true, $forcewrite=false)
Definition: Mpdf.php:4020
$maxPosR
Definition: Mpdf.php:315
ResetSpacing()
Definition: Mpdf.php:4566
$allowedCSStags
Definition: Mpdf.php:164
RestrictUnicodeFonts($res)
Definition: Mpdf.php:1686
$keywords
Definition: Mpdf.php:814
$img_dpi
Definition: Mpdf.php:184
$curlUserAgent
Definition: Mpdf.php:731
SetHeaderByName($name, $side='O', $write=false)
Definition: Mpdf.php:12658
$simpleTables
Definition: Mpdf.php:102
_getNormalLineheight($desc=false)
Definition: Mpdf.php:10992
$spanborder
Definition: Mpdf.php:245
$curlProxy
Definition: Mpdf.php:713
_advanceFloatMargins()
Definition: Mpdf.php:8760
_createHTMLheaderFooter($arr, $hf)
Definition: Mpdf.php:12527
$ignore_table_widths
Definition: Mpdf.php:146
$PDFXauto
Definition: Mpdf.php:73
read_short(&$fh)
Definition: Mpdf.php:19431
$flowingBlockAttr
Definition: Mpdf.php:735
SetLineHeight($FontPt='', $lh='')
Definition: Mpdf.php:11011
Line($x1, $y1, $x2, $y2)
Definition: Mpdf.php:3756
$tableClipPath
Definition: Mpdf.php:305
$barcode
Definition: Mpdf.php:902
$useFixedTextBaseline
Definition: Mpdf.php:39
$useDictionaryLBR
Definition: Mpdf.php:227
$arabHex
Definition: Mpdf.php:385
StartTransform($returnstring=false)
Definition: Mpdf.php:26574
$DeflMargin
Definition: Mpdf.php:775
$kwt_Links
Definition: Mpdf.php:436
Output($name='', $dest='')
Definition: Mpdf.php:9478
$whitelistStreamWrappers
Definition: Mpdf.php:185
GetJspacing($nc, $ns, $w, $inclCursive, &$cOTLdata)
Definition: Mpdf.php:4601
SetFillColor($r, $g=-1, $b=-1, $col4=-1, $return=false)
Definition: Mpdf.php:3441
$cellPaddingB
Definition: Mpdf.php:649
$CoreFonts
Definition: Mpdf.php:784
$cellTextAlign
Definition: Mpdf.php:553
inlineObject($type, $x, $y, $objattr, $Lmargin, $widthUsed, $maxWidth, $lineHeight, $paint=false, $is_table=false)
Definition: Mpdf.php:9085
$useKerning
Definition: Mpdf.php:64
_charDefined(&$cw, $u)
Definition: Mpdf.php:3492
TableCheckMinWidth($maxwidth, $forcewrap=0, $textbuffer=[], $checkletter=false)
Definition: Mpdf.php:19052
$DrawColor
Definition: Mpdf.php:798
SetAuthor($author)
Definition: Mpdf.php:1815
$smCapsStretch
Definition: Mpdf.php:83
_fixTableBorders(&$table)
Definition: Mpdf.php:21313
$thead_font_style
Definition: Mpdf.php:633
$CJKforceend
Definition: Mpdf.php:50
$autoArabic
Definition: Mpdf.php:48
Cell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=0, $link='', $currentx=0, $lcpaddingL=0, $lcpaddingR=0, $valign='M', $spanfill=0, $exactWidth=false, $OTLdata=false, $textvar=0, $lineBox=false)
Definition: Mpdf.php:4734
$saveHTMLFooterE_height
Definition: Mpdf.php:418
$additionalXmpRdf
Definition: Mpdf.php:820
$tabSpaces
Definition: Mpdf.php:134
$keep_block_together
Definition: Mpdf.php:597
$PDFAXwarnings
Definition: Mpdf.php:273
$decimal_align
Definition: Mpdf.php:53
purify_utf8($html, $lo=true)
Definition: Mpdf.php:26026
_setBidiCodes($mode='start', $bdf='')
Definition: Mpdf.php:25503
_saveTextBuffer($t, $link='', $intlink='', $return=false)
Definition: Mpdf.php:15761
$internallink
Definition: Mpdf.php:577
$autoMarginPadding
Definition: Mpdf.php:109
SetFColor($col, $return=false)
Definition: Mpdf.php:3396
$cellLineStackingStrategy
Definition: Mpdf.php:555
$biDirectional
Definition: Mpdf.php:177
$lSpacingCSS
Definition: Mpdf.php:253
$linebreakjustfinished
Definition: Mpdf.php:331
Text($x, $y, $txt, $OTLdata=[], $textvar=0, $aixextra='', $coordsys='', $return=false)
Definition: Mpdf.php:4348
$base_table_properties
Definition: Mpdf.php:443
is_utf8(&$string)
Definition: Mpdf.php:26004
$CurrCol
Definition: Mpdf.php:499
PaintDivLnBorder($state=0, $blvl=0, $h=0)
Definition: Mpdf.php:17822
$arabGlyphs
Definition: Mpdf.php:384
transformScale($s_x, $s_y, $x='', $y='', $returnstring=false)
Definition: Mpdf.php:26592
$lineheight
Definition: Mpdf.php:580
$SHYcharmin
Definition: Mpdf.php:121
$defaultheaderline
Definition: Mpdf.php:189
$charset_in
Definition: Mpdf.php:526
$kwt_Reference
Definition: Mpdf.php:358
$defaultCSS
Definition: Mpdf.php:521
$splitTableBorderWidth
Definition: Mpdf.php:55
shrinkTable(&$table, $k)
Definition: Mpdf.php:19287
$watermark_font
Definition: Mpdf.php:626
watermark($texte, $angle=45, $fontsize=96, $alpha=0.2)
Definition: Mpdf.php:10481
Annotation($text, $x=0, $y=0, $icon='Note', $author='', $subject='', $opacity=0, $colarray=false, $popup='', $file='')
Definition: Mpdf.php:9871
$originalMbEnc
Definition: Mpdf.php:605
AliasNbPages($alias='{nb}')
Definition: Mpdf.php:1876
$InlineAnnots
Definition: Mpdf.php:394
$ignore_invalid_utf8
Definition: Mpdf.php:163
$collapseBlockMargins
Definition: Mpdf.php:110
$lastblockbottommargin
Definition: Mpdf.php:293
getBasicOTLdata(&$chunkOTLdata, $unicode, &$is_strong)
Definition: Mpdf.php:25474
DisableTags($str='')
Definition: Mpdf.php:19037
PrintBodyBackgrounds()
Definition: Mpdf.php:2243
$compress
Definition: Mpdf.php:750
setHiEntitySubstitutions()
Definition: Mpdf.php:25980
ResetStyles()
Definition: Mpdf.php:19028
__construct(array $config=[])
Definition: Mpdf.php:1032
$spanbgcolor
Definition: Mpdf.php:550
SetVisibility($v)
Definition: Mpdf.php:1940
transformRotate($angle, $x='', $y='', $returnstring=false)
Definition: Mpdf.php:26647
_setListMarker($listitemtype, $listitemimage, $listitemposition)
Definition: Mpdf.php:15342
columnAdjustPregReplace($type, $xadj, $yadj, $pattern, $subject)
Definition: Mpdf.php:24892
$shrin_k1
Definition: Mpdf.php:338
$inMeter
Definition: Mpdf.php:236
$useTibetanLBR
Definition: Mpdf.php:228
$use_kwt
Definition: Mpdf.php:430
$tbrot_BMoutlines
Definition: Mpdf.php:362
$checkSIP
Definition: Mpdf.php:268
Write($h, $txt, $currentx=0, $link='', $directionality='ltr', $align='', $fill=0)
Definition: Mpdf.php:6222
$tbrot_h
Definition: Mpdf.php:602
$iterationCounter
Definition: Mpdf.php:81
$backupSubsFont
Definition: Mpdf.php:85
$h2toc
Definition: Mpdf.php:52
$ColDetails
Definition: Mpdf.php:511
$arabVowels
Definition: Mpdf.php:388
$fonttrans
Definition: Mpdf.php:87
_SetTextRendering($mode)
Definition: Mpdf.php:8806
$bookmarkStyles
Definition: Mpdf.php:57
$annotMargin
Definition: Mpdf.php:141
$lMargin
Definition: Mpdf.php:766
$tbrot_Links
Definition: Mpdf.php:595
$baselineSub
Definition: Mpdf.php:298
$autoPadding
Definition: Mpdf.php:133
$showWatermarkImage
Definition: Mpdf.php:205
AddColumn()
Definition: Mpdf.php:24383
$usingCoreFont
Definition: Mpdf.php:660
RoundedRect($x, $y, $w, $h, $r, $style='')
Definition: Mpdf.php:10619
$tabletheadjustfinished
Definition: Mpdf.php:659
setMBencoding($enc)
Definition: Mpdf.php:1700
$original_default_font_size
Definition: Mpdf.php:624
$InHTMLFooter
Definition: Mpdf.php:806
$table_borders_separate
Definition: Mpdf.php:442
NewColumn()
Definition: Mpdf.php:24389
printobjectbuffer($is_table=false, $blockdir=false)
Definition: Mpdf.php:7095
$interpolateImages
Definition: Mpdf.php:41
_tableGetMaxRowHeight($table, $row)
Definition: Mpdf.php:20724
$persianHex
Definition: Mpdf.php:387
$fixedPosBlockSave
Definition: Mpdf.php:313
$tfoot_font_weight
Definition: Mpdf.php:638
AddFont($family, $style='')
Definition: Mpdf.php:3813
PaintDivBB($divider='', $blockstate=0, $blvl=0)
Definition: Mpdf.php:16622
$listtype
Definition: Mpdf.php:561
$defaultCssFile
Definition: Mpdf.php:522
_putextgstates()
Definition: Mpdf.php:23307
$ignore_table_percents
Definition: Mpdf.php:147
$columnForms
Definition: Mpdf.php:402
SetSpacing($cs, $ws)
Definition: Mpdf.php:4578
$tempDir
Definition: Mpdf.php:284
initialiseBlock(&$blk)
Definition: Mpdf.php:14772
$allow_charset_conversion
Definition: Mpdf.php:166
$ChangeColumn
Definition: Mpdf.php:509
$bulletarray
Definition: Mpdf.php:372
_reverseTableDir(&$table)
Definition: Mpdf.php:21830
$watermark_size
Definition: Mpdf.php:138
_setAutoFooterHeight(&$htmlf)
Definition: Mpdf.php:10425
$outerblocktags
Definition: Mpdf.php:826
$ColActive
Definition: Mpdf.php:497
$SVGcolors
Definition: Mpdf.php:257
IndexEntry($txt, $xref='')
Definition: Mpdf.php:23940
$orig_lMargin
Definition: Mpdf.php:450
AddCustomProperty($key, $value)
Definition: Mpdf.php:1833
$backupSIPFont
Definition: Mpdf.php:86
$tfoot_font_smCaps
Definition: Mpdf.php:640
CircularText($x, $y, $r, $text, $align='top', $fontfamily='', $fontsize=0, $fontstyle='', $kerning=120, $fontwidth=100, $divider='')
Definition: Mpdf.php:10609
_enddoc()
Definition: Mpdf.php:9941
$defaultfooterfontstyle
Definition: Mpdf.php:191
$tbrot_x0
Definition: Mpdf.php:600
$svgClasses
Definition: Mpdf.php:208
$saveTableCounter
Definition: Mpdf.php:414
$innerblocktags
Definition: Mpdf.php:827
$spotColorIDs
Definition: Mpdf.php:256
$show_marks
Definition: Mpdf.php:427
$tMargin
Definition: Mpdf.php:767
WriteCell($w, $h=0, $txt='', $border=0, $ln=0, $align='', $fill=0, $link='', $currentx=0)
Definition: Mpdf.php:4524
Image($file, $x, $y, $w=0, $h=0, $type='', $link='', $paint=true, $constrain=true, $watermark=false, $shownoimg=true, $allowvector=true)
Definition: Mpdf.php:8840
$HTMLFooterE
Definition: Mpdf.php:478
$indexUseSubentries
Definition: Mpdf.php:43
restoreInlineProperties(&$saved)
Definition: Mpdf.php:6266
Shaded_box($text, $font='', $fontstyle='B', $szfont='', $width='70%', $style='DF', $radius=2.5, $fill='#FFFFFF', $color='#000000', $pad=2)
Definition: Mpdf.php:10667
IndexEntrySee($txta, $txtb)
Definition: Mpdf.php:23981
$columnbuffer
Definition: Mpdf.php:510
WriteHTML($html, $mode=HTMLParserMode::DEFAULT_MODE, $init=true, $close=true)
Definition: Mpdf.php:13145
docPageSettings($num=0)
Definition: Mpdf.php:11679
_dounderline($x, $y, $txt, $OTLdata=false, $textvar=0)
Definition: Mpdf.php:10467
$allowCJKorphans
Definition: Mpdf.php:61
$available_CJK_fonts
Definition: Mpdf.php:473
$autoVietnamese
Definition: Mpdf.php:47
SetAnchor2Bookmark($x)
Definition: Mpdf.php:1871
$autoScriptToLang
Definition: Mpdf.php:45
$pageBackgrounds
Definition: Mpdf.php:345
GetFirstBlockFill()
Definition: Mpdf.php:6322
SetCompression($compress)
Definition: Mpdf.php:1793
_tableColumnWidth(&$table, $firstpass=false)
Definition: Mpdf.php:19533
$n_ocg_hidden
Definition: Mpdf.php:742
_puthtmlheaders()
Definition: Mpdf.php:9662
$displayDefaultOrientation
Definition: Mpdf.php:162
$formobjects
Definition: Mpdf.php:392
columnAdjustAdd($type, $k, $xadj, $yadj, $a, $b, $c=0, $d=0, $e=0, $f=0)
Definition: Mpdf.php:26850
SetDColor($col, $return=false)
Definition: Mpdf.php:3380
tabs2spaces_callback($matches)
Definition: Mpdf.php:27120
OverWrite($file_in, $search, $replacement, $dest=Destination::DOWNLOAD, $file_out="mpdf")
Definition: Mpdf.php:27132
$allow_output_buffering
Definition: Mpdf.php:132
$ColumnAdjust
Definition: Mpdf.php:529
AutosizeText($text, $w, $font, $style, $szfont=72)
Definition: Mpdf.php:25361
AddLink()
Definition: Mpdf.php:4303
_getCharWidth(&$cw, $u, $isdef=true)
Definition: Mpdf.php:3471
$curlProxyAuth
Definition: Mpdf.php:722
$colorarray
Definition: Mpdf.php:575
Rotate($angle, $x=-1, $y=-1)
Definition: Mpdf.php:10587
$tbrot_y0
Definition: Mpdf.php:599
$pageHTMLfooters
Definition: Mpdf.php:456
$divbegin
Definition: Mpdf.php:547
$aliasNbPgGp
Definition: Mpdf.php:823
$HTMLFooter
Definition: Mpdf.php:476
$floatbuffer
Definition: Mpdf.php:368
$list_indent_default
Definition: Mpdf.php:152
$inlineDisplayOff
Definition: Mpdf.php:264
$hyphenationDictionaryFile
Definition: Mpdf.php:324
$tablebuffer
Definition: Mpdf.php:593
$svgAutoFont
Definition: Mpdf.php:207
$pjustfinished
Definition: Mpdf.php:564
$FontSize
Definition: Mpdf.php:797
_printListBullet($x, $y, $size, $type, $color)
Definition: Mpdf.php:7667
$onlyCoreFonts
Definition: Mpdf.php:165
$list_indent_first_level
Definition: Mpdf.php:151
$nbpgSuffix
Definition: Mpdf.php:130
getFontDescriptor()
Definition: Mpdf.php:27397
$PageAnnots
Definition: Mpdf.php:405
$maxPosL
Definition: Mpdf.php:314
saveInlineProperties()
Definition: Mpdf.php:6236
DefHTMLFooterByName($name, $html)
Definition: Mpdf.php:12684
$cell_border_dominance_R
Definition: Mpdf.php:333
SetWatermarkText($txt='', $alpha=-1)
Definition: Mpdf.php:13005
printkwtbuffer()
Definition: Mpdf.php:25145
printfloatbuffer()
Definition: Mpdf.php:25323
$basepath
Definition: Mpdf.php:582
$ZoomMode
Definition: Mpdf.php:809
$bodyBackgroundColor
Definition: Mpdf.php:349
$watermark_pos
Definition: Mpdf.php:139
$outerfilled
Definition: Mpdf.php:339
$HTMLheaderPageForms
Definition: Mpdf.php:463
$defDrawColor
Definition: Mpdf.php:260
$list_marker_offset
Definition: Mpdf.php:154
$page_box
Definition: Mpdf.php:425
$OTLtags
Definition: Mpdf.php:224
_table2cellBorder(&$tableb, &$cbdb, &$cellb, $bval)
Definition: Mpdf.php:21301
all_entities_to_utf8($txt)
Definition: Mpdf.php:26080
$plainCell_properties
Definition: Mpdf.php:337
watermarkImg($src, $alpha=0.2)
Definition: Mpdf.php:10566
AddGBFont()
Definition: Mpdf.php:10826
SetWatermarkImage($src, $alpha=-1, $size='D', $pos='F')
Definition: Mpdf.php:13013
$tfoot_valign_default
Definition: Mpdf.php:641
$divheight
Definition: Mpdf.php:549
SetFooterByName($name, $side='O')
Definition: Mpdf.php:12666
$table_border_attr_set
Definition: Mpdf.php:650
GetCharWidth($c, $addSubset=true)
Definition: Mpdf.php:3597
$gradients
Definition: Mpdf.php:356
EndLayer()
Definition: Mpdf.php:2780
$defaultPagebreakType
Definition: Mpdf.php:42
$watermarkImgAlphaBlend
Definition: Mpdf.php:97
$tbrot_maxw
Definition: Mpdf.php:591
StopTransform($returnstring=false)
Definition: Mpdf.php:26583
SetBasePath($str='')
Definition: Mpdf.php:11405
ResetMargins()
Definition: Mpdf.php:1716
SetY($y)
Definition: Mpdf.php:9460
$tbrot_Annots
Definition: Mpdf.php:399
$docTemplate
Definition: Mpdf.php:380
Ellipse($x, $y, $rx, $ry, $style='S')
Definition: Mpdf.php:25339
$baselineSup
Definition: Mpdf.php:297
$directionality
Definition: Mpdf.php:608
$nonPrintMargin
Definition: Mpdf.php:70
SetBackground(&$properties, &$maxwidth)
Definition: Mpdf.php:2148
$curlCaCertificate
Definition: Mpdf.php:695
Ln($h='', $collapsible=0)
Definition: Mpdf.php:9352
$text_input_as_HTML
Definition: Mpdf.php:178
$subject
Definition: Mpdf.php:812
$docTemplateContinue
Definition: Mpdf.php:381
cleanup()
Definition: Mpdf.php:1550
Definition: Otl.php:17
static getSizeFromName($name)
Definition: PageFormat.php:16
static get_ucd_record($code)
Definition: Ucdn.php:116
const SCRIPT_LATIN
Definition: Ucdn.php:13
const SCRIPT_ARABIC
Definition: Ucdn.php:18
const UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK
Definition: Ucdn.php:654
static get($array, $key, $default=null)
Definition: Arrays.php:8
static containsPercentChar($string)
static removePercentChar($string)
static codeHex2utf($hex, $lo=true)
Definition: UtfString.php:57
static strcode2utf($str, $lo=true)
Definition: UtfString.php:17
static code2utf($num, $lo=true)
Definition: UtfString.php:35
Definition: Barcode.php:3
trait FpdiTrait
Definition: FpdiTrait.php:26
useTemplate($tpl, $x=0, $y=0, $width=null, $height=null, $adjustPageSize=false)
Definition: FpdiTrait.php:111
importPage($pageNumber, $box=PageBoundaries::CROP_BOX, $groupXObject=true)
Definition: FpdiTrait.php:168
setSourceFile($file)
Definition: FpdiTrait.php:211
AddPage($orientation='', $size='', $rotation=0)
Link($x, $y, $w, $h, $link)
SetLink($link, $y=0, $page=-1)
SetFont($family, $style='', $size=0)
SetFontSize($size)
SetLineWidth($width)
$html
inisialisasi variabel dari hasil perekaman halaman
Definition: nota.php:119
$path
Definition: out.php:3
if(strstr($tempfilename,'/')||strstr($tempfilename,'\\')) $name
Definition: out.php:11
$dest
Definition: out.php:12
$aarr
Definition: subs_core.php:2
$zarr
Definition: subs_core.php:128
$sarr
Definition: subs_core.php:318
$subsarray